Update upstream Chromium

Revision: b84bb501f83db00e48e2b2a43b2f326afb179e98
diff --git a/AUTHORS b/AUTHORS
index 4810a10..253a383 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -13,11 +13,13 @@
 Aaron Randolph <aaron.randolph@gmail.com>
 Abhijeet Kandalkar <abhijeet.k@samsung.com>
 Abhishek Agarwal <abhishek.a21@samsung.com>
+Abhishek Singh <abhi.rathore@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>
+Abhishek Kanike <abhishek.ka@samsung.com>
 Ajay Berwal <ajay.berwal@samsung.com>
 Ajay Berwal <a.berwal@samsung.com>
 Ajith Kumar V <ajith.v@samsung.com>
@@ -26,6 +28,7 @@
 Alex Gartrell <agartrell@cmu.edu>
 Alex Henrie <alexhenrie24@gmail.com>
 Alex Scheele <alexscheele@gmail.com>
+Alexander Shalamov <alexander.shalamov@intel.com>
 Alexander Sulfrian <alexander@sulfrian.net>
 Alexandre Abreu <wiss1976@gmail.com>
 Alexandru Chiculita <achicu@adobe.com>
@@ -47,6 +50,8 @@
 Andrew Tulloch <andrew@tullo.ch>
 Anish Patankar <anish.p@samsung.com>
 Ankit Kumar <ankit2.kumar@samsung.com>
+Ankur Verma <ankur1.verma@samsung.com>
+Anne Kao <annekao94@gmail.com>
 Anssi Hannula <anssi.hannula@iki.fi>
 Antonio Gomes <a1.gomes@sisa.samsung.com>
 Anuj Kumar Sharma <anujk.sharma@samsung.com>
@@ -59,6 +64,7 @@
 Arunoday Sarkar <a.sarkar.arun@gmail.com>
 Arunprasad Rajkumar <ararunprasad@gmail.com>
 Arunprasad Rajkumar <arurajku@cisco.com>
+Ashlin Joseph <ashlin.j@samsung.com>
 Attila Dusnoki <dati91@gmail.com>
 Avinaash Doreswamy <avi.nitk@samsung.com>
 Balazs Kelemen <b.kelemen@samsung.com>
@@ -68,6 +74,7 @@
 Bem Jones-Bey <bjonesbe@adobe.com>
 Ben Fiola <benfiola@gmail.com>
 Ben Karel <eschew@gmail.com>
+Ben Noordhuis <ben@strongloop.com>
 Benjamin Dupont <bedupont@cisco.com>
 Benjamin Jemlich <pcgod99@gmail.com>
 Bernard Cafarelli <voyageur@gentoo.org>
@@ -100,6 +107,7 @@
 Chris Greene <cwgreene@amazon.com>
 Chris Harrelson <chrishtr@gmail.com>
 Chris Nardi <hichris123@gmail.com>
+Chris Tserng <tserng@amazon.com>
 Chris Vasselli <clindsay@gmail.com>
 Christophe Dumez <ch.dumez@samsung.com>
 Christopher Dale <chrelad@gmail.com>
@@ -111,10 +119,12 @@
 Daegyu Lee <na7jun8gi@gmail.com>
 Dai Chunyang <chunyang.dai@intel.com>
 Daiwei Li <daiweili@suitabletech.com>
+Dan McCombs <overridex@gmail.com>
 Daniel Bomar <dbdaniel42@gmail.com>
 Daniel Carvalho Liedke <dliedke@gmail.com>
 Daniel Imms <daniimms@amazon.com>
 Daniel Johnson <danielj41@gmail.com>
+Daniel Lockyer <thisisdaniellockyer@gmail.com>
 Daniel Nishi <dhnishi@gmail.com>
 Daniel Platz <daplatz@googlemail.com>
 Daniel Shaulov <dshaulov@ptc.com>
@@ -122,10 +132,12 @@
 Darshini KN <kn.darshini@samsung.com>
 David Benjamin <davidben@mit.edu>
 David Erceg <erceg.david@gmail.com>
+David Fox <david@davidjfox.com>
 David Futcher <david.mike.futcher@gmail.com>
 David Leen <davileen@amazon.com>
 David McAllister <mcdavid@amazon.com>
 David Spellman <dspell@amazon.com>
+Dax Kelson <dkelson@gurulabs.com>
 Debashish Samantaray <d.samantaray@samsung.com>
 Deepak Dilip Borade <deepak.db@samsung.com>
 Deepak Mittal <deepak.m1@samsung.com>
@@ -138,15 +150,18 @@
 Dominic Jodoin <dominic.jodoin@gmail.com>
 Dominik Röttsches <dominik.rottsches@intel.com>
 Don Woodward <woodward@adobe.com>
+Dongie Agnir <dongie.agnir@gmail.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) <eblima@gmail.com>
 Eduardo Lima (Etrunko) <eduardo.lima@intel.com>
 Edward Baker <edward.baker@intel.com>
 Edward Crossman <tedoc2000@gmail.com>
+Eero Häkkinen <eero.hakkinen@intel.com>
 Eero Häkkinen <e.hakkinen@samsung.com>
 Egor Starkov <egor.starkov@samsung.com>
 Ehsan Akhgari <ehsan.akhgari@gmail.com>
@@ -165,9 +180,11 @@
 Fabien Tassin <fta@sofaraway.org>
 Felix H. Dahlke <fhd@ubercode.de>
 Fernando Jiménez Moreno <ferjmoreno@gmail.com>
+Finbar Crago <finbar.crago@gmail.com>
 François Beaufort <beaufort.francois@gmail.com>
 Francois Kritzinger <francoisk777@gmail.com>
 Francois Rauch <leopardb@gmail.com>
+Frédéric Jacob <frederic.jacob.78@gmail.com>
 Frédéric Wang <fred.wang@free.fr>
 Gaetano Mendola <mendola@gmail.com>
 Gajendra N <gajendra.n@samsung.com>
@@ -187,18 +204,22 @@
 Grzegorz Czajkowski <g.czajkowski@samsung.com>
 Guangzhen Li <guangzhen.li@intel.com>
 Gurpreet Kaur <k.gurpreet@samsung.com>
-Gyuyoung Kim <gyuyoung.kim@samsung.com>
+Gustav Tiger <gustav.tiger@sonymobile.com>
+Gyuyoung Kim <gyuyoung.kim@navercorp.com>
 Gzob Qq <gzobqq@gmail.com>
 Habib Virji <habib.virji@samsung.com>
 Haitao Feng <haitao.feng@intel.com>
+Halley Zhao <halley.zhao@intel.com>
 Halton Huo <halton.huo@intel.com>
 Haojian Wu <hokein.wu@gmail.com>
+Hari Singh <hari.singh1@samsung.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>
+Holger Kraus <kraush@amazon.com>
 Hong Zheng <hong.zheng@intel.com>
 Hongbo Min <hongbo.min@intel.com>
 Horia Olaru <horia.olaru@gmail.com>
@@ -210,10 +231,13 @@
 Hyunjune Kim <hyunjune.kim@samsung.com>
 Hyunki Baik <hyunki.baik@samsung.com>
 Hyungwook Lee <withlhw@gmail.com>
+Hyungwook Lee <hyungwook.lee@navercorp.com>
 Ian Cullinan <cullinan@amazon.com>
 Ian Scott <ian.scott@arteris.com>
 Ibrar Ahmed <ibrar.ahmad@gmail.com>
+Ilia K <ki.stfu@gmail.com>
 Ion Rosca <rosca@adobe.com>
+Isaac Reilly <reillyi@amazon.com>
 Ivan Sham <ivansham@amazon.com>
 J. Ryan Stinnett <jryans@chromium.org>
 Jacob Mandelson <jacob@mandelson.org>
@@ -228,11 +252,13 @@
 James Vega <vega.james@gmail.com>
 James Wei <james.wei@intel.com>
 James Willcox <jwillcox@litl.com>
+Jan Sauer <jan@jansauer.de>
 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 Oster <jay@kodewerx.org>
 Jay Soffian <jaysoffian@gmail.com>
 Jeado Ko <haibane84@gmail.com>
 Jeongeun Kim <je_julie.kim@samsung.com>
@@ -247,9 +273,11 @@
 Jingwei Liu <kingweiliu@gmail.com>
 Jingyi Wei <wjywbs@gmail.com>
 Jinho Bang <jinho.bang@samsung.com>
+Jinkyu Seong <jinkyu.seong@lge.com>
 Jinwoo Song <jinwoo7.song@samsung.com>
 Jitendra Kumar Sahoo <jitendra.ks@samsung.com>
 Joachim Bauch <mail@joachim-bauch.de>
+Joachim Bauch <jbauch@webrtc.org>
 Joe Knoll <joe.knoll@workday.com>
 Joe Thomas <mhx348@motorola.com>
 Joel Stanley <joel@jms.id.au>
@@ -270,6 +298,8 @@
 Joshua Roesslein <jroesslein@gmail.com>
 Josué Ratelle <jorat1346@gmail.com>
 Juhui Lee <juhui24.lee@samsung.com>
+Julien Brianceau <jbriance@cisco.com>
+Julien Isorce <j.isorce@samsung.com>
 Julien Racle <jracle@logitech.com>
 Jun Jiang <jun.a.jiang@intel.com>
 Junchao Han <junchao.han@intel.com>
@@ -286,13 +316,17 @@
 Kaustubh Atrawalkar <kaustubh.ra@gmail.com>
 Kaustubh Atrawalkar <kaustubh.a@samsung.com>
 Keene Pan <keenepan@linpus.com>
+Keith Chen <keitchen@amazon.com>
 Kenneth Rohde Christiansen <kenneth.r.christiansen@intel.com>
+Kenneth Zhou <knthzh@gmail.com>
 Keonho Kim <keonho07.kim@samsung.com>
+Ketan Goyal <ketan.goyal@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>
+Kirill Bobyrev <kirillbobyrev@gmail.com>
 Kirk Shoop <kirk.shoop@microsoft.com>
 Klemen Forstnerič <klemen.forstneric@gmail.com>
 Krishna Chaitanya <krish.botta@samsung.com>
@@ -311,6 +345,9 @@
 Lauri Oherd <lauri.oherd@gmail.com>
 Legend Lee <guanxian.li@intel.com>
 Leith Bade <leith@leithalweapon.geek.nz>
+Leo Wolf <jclw@ymail.com>
+Leon Han <leon.han@intel.com>
+Leung Wing Chung <lwchkg@gmail.com>
 Li Yin <li.yin@intel.com>
 Lidwine Genevet <lgenevet@cisco.com>
 Lionel Landwerlin <lionel.g.landwerlin@intel.com>
@@ -329,8 +366,10 @@
 Mao Yujie <yujie.mao@intel.com>
 Marco Rodrigues <gothicx@gmail.com>
 Mario Sanchez Prada <mario.prada@samsung.com>
+Mariusz Mlynski <marius.mlynski@gmail.com>
 Mark Hahnenberg <mhahnenb@andrew.cmu.edu>
 Mark Seaborn <mrs@mythic-beasts.com>
+Martijn Croonen <martijn@martijnc.be>
 Martin Bednorz <m.s.bednorz@gmail.com>
 Martina Kollarova <martina.kollarova@intel.com>
 Masahiro Yado <yado.masa@gmail.com>
@@ -339,6 +378,7 @@
 Mathieu Meisser <mmeisser@logitech.com>
 Matt Arpidone <mma.public@gmail.com>
 Matt Strum <mstrum@amazon.com>
+Matthew Bauer <mjbauer95@gmail.com>
 Matthew Demarest <demarem@amazon.com>
 Matthew Robertson <matthewrobertson03@gmail.com>
 Matthew Turk <matthewturk@gmail.com>
@@ -357,7 +397,9 @@
 Mihai Tica <mitica@adobe.com>
 Mike Tilburg <mtilburg@adobe.com>
 Mikhail Pozdnyakov <mikhail.pozdnyakov@intel.com>
+Milton Chiang <milton.chiang@mediatek.com>
 Mingmin Xie <melvinxie@gmail.com>
+Minsoo Max Koo <msu.koo@samsung.com>
 Mirela Budaes <mbudaes@gmail.com>
 Mirela Budaes <mbudaes@adobe.com>
 Mitchell Rosen <mitchellwrosen@chromium.org>
@@ -451,6 +493,7 @@
 Rosen Dash <rosen.dash@gmail.com>
 ruben <chromium@hybridsource.org>
 Ruben Terrazas <rubentopo@gmail.com>
+Rufus Hamade <rufus.hamade@imgtec.com>
 Ruiyi Luo <luoruiyi2008@gmail.com>
 Ryan Ackley <ryanackley@gmail.com>
 Ryan Norton <rnorton10@gmail.com>
@@ -462,10 +505,12 @@
 Sam Larison <qufighter@gmail.com>
 Sam McDonald <sam@sammcd.com>
 Sanghyun Park <sh919.park@samsung.com>
+Sanghyup Lee <sh53.lee@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@gmail.com>
 Sarath Singapati <s.singapati@samsung.com>
 Saravanan KR <sramajay@cisco.com>
 Sathish Kuppuswamy <sathish.kuppuswamy@intel.com>
@@ -480,14 +525,18 @@
 Sergiy Byelozyorov <rryk.ua@gmail.com>
 Seshadri Mahalingam <seshadri.mahalingam@gmail.com>
 Sevan Janiyan <venture37@geeklan.co.uk>
+Shahriar Rostami <shahriar.rostami@gmail.com>
 ShankarGanesh K <blr.bmlab@gmail.com>
 Shanmuga Pandi M <shanmuga.m@samsung.com>
+Shail Singhal <shail.s@samsung.com>
+Shashi Kumar <sk.kumar@samsung.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 <liushouqun@xiaomi.com>
 Shouqun Liu <shouqun.liu@intel.com>
 Shreeram Kushwaha <shreeram.k@samsung.com>
 Shreyas Gopal <shreyas.g@samsung.com>
@@ -497,6 +546,7 @@
 Siva Kumar Gunturi <siva.gunturi@samsung.com>
 Sohan Jyoti Ghosh <sohan.jyoti@samsung.com>
 Song YeWen <ffmpeg@gmail.com>
+Sooho Park <sooho1000@gmail.com>
 Soren Dreijer <dreijerbit@gmail.com>
 Srirama Chandra Sekhar Mogali <srirama.m@samsung.com>
 Stephen Searles <stephen.searles@gmail.com>
@@ -509,12 +559,15 @@
 Sungguk Lim <limasdf@gmail.com>
 Sungmann Cho <sungmann.cho@gmail.com>
 Sungmann Cho <sungmann.cho@navercorp.com>
+Sunitha Srivatsa <srivats@amazon.com>
 Suyash Sengar <suyash.s@samsung.com>
 Sunil Ratnu <sunil.ratnu@samsung.com>
+Suvanjan Mukherjee <suvanjanmukherjee@gmail.com>
 Swati Jaiswal <swa.jaiswal@samsung.com>
 Sylvain Zimmer <sylvinus@gmail.com>
 Szymon Piechowicz <szymonpiechowicz@o2.pl>
 Takeshi Kurosawa <taken.spc@gmail.com>
+Tanay Chowdhury <tanay.c@samsung.com>
 Tapu Kumar Ghose <ghose.tapu@gmail.com>
 Taylor Price <trprice@gmail.com>
 Ted Kim <neot0000@gmail.com>
@@ -527,10 +580,14 @@
 Tiago Vignatti <tiago.vignatti@intel.com>
 Tim Ansell <mithro@mithis.com>
 Timo Reimann <ttr314@googlemail.com>
+Tom Harwood <tfh@skip.org>
 Torsten Kurbad <google@tk-webart.de>
+Tomas Popela <tomas.popela@gmail.com>
 Trevor Perrin <unsafe@trevp.net>
 U. Artie Eoff <ullysses.a.eoff@intel.com>
 Umar Hansa <umar.hansa@gmail.com>
+Upendra Gowda <upendrag.gowda@gmail.com>
+Vaibhav Agrawal <vaibhav1.a@samsung.com>
 Vamshikrishna Yellenki <vamshi@motorola.com>
 Vani Hegde <vani.hegde@samsung.com>
 Vartul Katiyar <vartul.k@samsung.com>
@@ -545,6 +602,8 @@
 Vivek Galatage <vivek.vg@samsung.com>
 Volker Sorge <volker.sorge@gmail.com>
 Wesley Lancel <wesleylancel@gmail.com>
+Wesley Wigham <t-weswig@microsoft.com>
+Wesley Wigham <wwigham@gmail.com>
 Will Hirsch <chromium@willhirsch.co.uk>
 William Xie <william.xie@intel.com>
 Xiang Long <xiang.long@intel.com>
@@ -565,7 +624,9 @@
 Yong Shin <sy3620@gmail.com>
 Yongsheng Zhu <yongsheng.zhu@intel.com>
 Yoshinori Sano <yoshinori.sano@gmail.com>
+Youngho Seo <hazivoo@gmail.com>
 YoungKi Hong <simon.hong81@gmail.com>
+Youngsoo Choi <kenshin.choi@samsung.com>
 Youngsun Suh <zard17@gmail.com>
 Yumikiyo Osanai <yumios.art@gmail.com>
 Yunchao He <yunchao.he@intel.com>
@@ -578,6 +639,7 @@
 Zhuoyu Qian <zhuoyu.qian@samsung.com>
 Ziran Sun <ziran.sun@samsung.com>
 Zoltan Herczeg <zherczeg.u-szeged@partner.samsung.com>
+Zoltan Kuscsik <zoltan.kuscsik@linaro.org>
 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com>
 Yongha Lee <yongha78.lee@samsung.com>
 方觉 (Fang Jue) <fangjue23303@gmail.com>
@@ -588,15 +650,19 @@
 Chanho Park <parkch98@gmail.com>
 Payal Pandey <payal.pandey@samsung.com>
 Kenneth Strickland <ken.strickland@gmail.com>
-Olli Syrjälä <olli.syrjala@intel.com>
+Olli Raula (Old name Olli Syrjälä) <olli.raula@intel.com>
 Vishal Bhatnagar <vishal.b@samsung.com>
 Yunsik Jang <yunsik.jang@lge.com>
 Siddharth Bagai <b.siddharth@samsung.com>
+Andrei Borza <andrei.borza@gmail.com>
+anatoly techtonik <techtonik@gmail.com>
+Aleksandar Stojiljkovic <aleksandar.stojiljkovic@intel.com>
 
 BlackBerry Limited <*@blackberry.com>
 Code Aurora Forum <*@codeaurora.org>
 Comodo CA Limited
 Google Inc. <*@google.com>
+Hewlett-Packard Development Company, L.P. <*@hp.com>
 Igalia S.L. <*@igalia.com>
 NVIDIA Corporation <*@nvidia.com>
 Opera Software ASA <*@opera.com>
@@ -607,4 +673,4 @@
 Venture 3 Systems LLC <*@venture3systems.com>
 Yandex LLC <*@yandex-team.ru>
 ARM Holdings <*@arm.com>
-
+Macadamian <*@macadamian.com>
diff --git a/LICENSE b/LICENSE
index 972bb2e..a32e00c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2015 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
diff --git a/base/BUILD.gn b/base/BUILD.gn
index de282cf..e5f3c19 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/compiler/compiler.gni")
+import("//build/config/nacl/config.gni")
 import("//build/config/ui.gni")
 import("//testing/test.gni")
 
@@ -9,6 +11,16 @@
   import("//build/config/android/rules.gni")
 }
 
+config("base_flags") {
+  if (is_clang) {
+    cflags = [
+      # Don't die on dtoa code that uses a char as an array index.
+      # This is required solely for base/third_party/dmg_fp/dtoa_wrapper.cc.
+      "-Wno-char-subscripts",
+    ]
+  }
+}
+
 config("base_implementation") {
   defines = [ "BASE_IMPLEMENTATION" ]
 }
@@ -25,6 +37,16 @@
   }
 }
 
+if (is_nacl_nonsfi) {
+  # Must be in a config because of how GN orders flags (otherwise -Wall will
+  # appear after this, and turn it back on).
+  config("nacl_nonsfi_warnings") {
+    # file_util_posix.cc contains a function which is not
+    # being used by nacl_helper_nonsfi.
+    cflags = [ "-Wno-unused-function" ]
+  }
+}
+
 source_set("base_paths") {
   sources = [
     "base_paths.cc",
@@ -39,7 +61,7 @@
     "base_paths_win.h",
   ]
 
-  if (is_android || is_mac) {
+  if (is_android || is_mac || is_ios) {
     sources -= [ "base_paths_posix.cc" ]
   }
 
@@ -64,10 +86,10 @@
   sources = [
     "allocator/allocator_extension.cc",
     "allocator/allocator_extension.h",
-    "allocator/type_profiler_control.cc",
-    "allocator/type_profiler_control.h",
     "android/animation_frame_time_histogram.cc",
     "android/animation_frame_time_histogram.h",
+    "android/apk_assets.cc",
+    "android/apk_assets.h",
     "android/application_status_listener.cc",
     "android/application_status_listener.h",
     "android/base_jni_onload.cc",
@@ -80,7 +102,10 @@
     "android/command_line_android.h",
     "android/content_uri_utils.cc",
     "android/content_uri_utils.h",
+    "android/context_utils.cc",
+    "android/context_utils.h",
     "android/cpu_features.cc",
+    "android/cxa_demangle_stub.cc",
     "android/event_log.cc",
     "android/event_log.h",
     "android/field_trial_list.cc",
@@ -129,25 +154,21 @@
     "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",
+    "base64url.cc",
+    "base64url.h",
     "base_export.h",
     "base_switches.h",
     "basictypes.h",
@@ -167,8 +188,6 @@
     "callback_internal.cc",
     "callback_internal.h",
     "cancelable_callback.h",
-    "chromeos/memory_pressure_monitor.cc",
-    "chromeos/memory_pressure_monitor.h",
     "command_line.cc",
     "command_line.h",
     "compiler_specific.h",
@@ -187,6 +206,8 @@
     "deferred_sequenced_task_runner.h",
     "environment.cc",
     "environment.h",
+    "feature_list.cc",
+    "feature_list.h",
     "file_descriptor_posix.h",
     "file_version_info.h",
     "file_version_info_mac.h",
@@ -247,10 +268,14 @@
     "hash.cc",
     "hash.h",
     "id_map.h",
+    "ios/crb_protocol_observers.h",
+    "ios/crb_protocol_observers.mm",
     "ios/device_util.h",
     "ios/device_util.mm",
     "ios/ios_util.h",
     "ios/ios_util.mm",
+    "ios/ns_error_util.h",
+    "ios/ns_error_util.mm",
     "ios/scoped_critical_action.h",
     "ios/scoped_critical_action.mm",
     "ios/weak_nsobject.h",
@@ -270,6 +295,9 @@
     "mac/bind_objc_block.h",
     "mac/bundle_locations.h",
     "mac/bundle_locations.mm",
+    "mac/call_with_eh_frame.cc",
+    "mac/call_with_eh_frame.h",
+    "mac/call_with_eh_frame_asm.S",
     "mac/cocoa_protocols.h",
     "mac/dispatch_source_mach.cc",
     "mac/dispatch_source_mach.h",
@@ -287,8 +315,6 @@
     "mac/mac_util.mm",
     "mac/mach_logging.cc",
     "mac/mach_logging.h",
-    "mac/memory_pressure_monitor.cc",
-    "mac/memory_pressure_monitor.h",
     "mac/objc_property_releaser.h",
     "mac/objc_property_releaser.mm",
     "mac/os_crash_dumps.cc",
@@ -306,8 +332,6 @@
     "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",
@@ -322,10 +346,8 @@
     "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_loop_task_runner.cc",
+    "message_loop/message_loop_task_runner.h",
     "message_loop/message_pump.cc",
     "message_loop/message_pump.h",
     "message_loop/message_pump_android.cc",
@@ -368,11 +390,12 @@
     "pending_task.h",
     "pickle.cc",
     "pickle.h",
-    "port.h",
     "posix/eintr_wrapper.h",
     "posix/file_descriptor_shuffle.cc",
     "posix/global_descriptors.cc",
     "posix/global_descriptors.h",
+    "posix/safe_strerror.cc",
+    "posix/safe_strerror.h",
     "posix/unix_domain_socket_linux.cc",
     "posix/unix_domain_socket_linux.h",
     "power_monitor/power_monitor.cc",
@@ -393,14 +416,14 @@
     "profiler/alternate_timer.h",
     "profiler/native_stack_sampler.cc",
     "profiler/native_stack_sampler.h",
+    "profiler/native_stack_sampler_posix.cc",
+    "profiler/native_stack_sampler_win.cc",
     "profiler/scoped_profile.cc",
     "profiler/scoped_profile.h",
     "profiler/scoped_tracker.cc",
     "profiler/scoped_tracker.h",
     "profiler/stack_sampling_profiler.cc",
     "profiler/stack_sampling_profiler.h",
-    "profiler/stack_sampling_profiler_posix.cc",
-    "profiler/stack_sampling_profiler_win.cc",
     "profiler/tracked_time.cc",
     "profiler/tracked_time.h",
     "rand_util.cc",
@@ -410,8 +433,6 @@
     "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",
@@ -431,6 +452,8 @@
     "strings/latin1_string_conversions.h",
     "strings/nullable_string16.cc",
     "strings/nullable_string16.h",
+    "strings/pattern.cc",
+    "strings/pattern.h",
     "strings/safe_sprintf.cc",
     "strings/safe_sprintf.h",
     "strings/string16.cc",
@@ -525,6 +548,8 @@
     "threading/platform_thread_win.cc",
     "threading/post_task_and_reply_impl.cc",
     "threading/post_task_and_reply_impl.h",
+    "threading/sequenced_task_runner_handle.cc",
+    "threading/sequenced_task_runner_handle.h",
     "threading/sequenced_worker_pool.cc",
     "threading/sequenced_worker_pool.h",
     "threading/simple_thread.cc",
@@ -603,14 +628,14 @@
     "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/process_startup_helper.cc",
+    "win/process_startup_helper.h",
     "win/registry.cc",
     "win/registry.h",
     "win/resource_util.cc",
@@ -643,22 +668,45 @@
     "win/wrapped_window_proc.h",
   ]
 
+  if (is_ios) {
+    sources -= [
+      "files/file_path_watcher.cc",
+      "files/file_path_watcher.h",
+      "files/file_path_watcher_fsevents.cc",
+      "files/file_path_watcher_fsevents.h",
+      "files/file_path_watcher_kqueue.cc",
+      "files/file_path_watcher_kqueue.h",
+      "message_loop/message_pump_libevent.cc",
+      "message_loop/message_pump_libevent.h",
+
+      # These don't work and are unused on iOS.
+      "sync_socket.h",
+      "sync_socket_posix.cc",
+    ]
+  }
+
   sources -= [
     "sys_info_freebsd.cc",
     "sys_info_openbsd.cc",
   ]
 
-  configs += [ ":base_implementation" ]
+  data = []
+
+  configs += [
+    ":base_flags",
+    ":base_implementation",
+    "//build/config:precompiled_headers",
+  ]
 
   deps = [
-    ":base_static",
-    "//base/allocator:allocator_extension_thunks",
+    "//base/allocator:extension_thunks",
     "//base/third_party/dynamic_annotations",
     "//third_party/modp_b64",
   ]
 
   public_deps = [
     ":base_paths",
+    ":base_static",
     "//base/debug",
     "//base/json",
     "//base/memory",
@@ -687,8 +735,8 @@
 
     deps += [
       ":base_jni_headers",
-      "//third_party/ashmem",
       "//third_party/android_tools:cpu_features",
+      "//third_party/ashmem",
     ]
 
     # logging.cc uses the Android logging library.
@@ -711,27 +759,37 @@
     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",
     ]
+
+    if (is_nacl_nonsfi) {
+      set_sources_assignment_filter([])
+      sources += [ "posix/unix_domain_socket_linux.cc" ]
+      set_sources_assignment_filter(sources_assignment_filter)
+      sources -= [ "rand_util_nacl.cc" ]
+      configs += [ ":nacl_nonsfi_warnings" ]
+    } else {
+      sources -= [
+        "files/file_util.cc",
+        "files/file_util.h",
+        "files/file_util_posix.cc",
+        "message_loop/message_pump_libevent.cc",
+        "message_loop/message_pump_libevent.h",
+        "rand_util_posix.cc",
+      ]
+    }
   } else {
     # Remove NaCl stuff.
     sources -= [
@@ -743,6 +801,11 @@
 
   # Windows.
   if (is_win) {
+    sources += [
+      "profiler/win32_stack_frame_unwinder.cc",
+      "profiler/win32_stack_frame_unwinder.h",
+    ]
+
     sources -= [
       "message_loop/message_pump_libevent.cc",
       "strings/string16.cc",
@@ -752,6 +815,30 @@
       "sha1_win.cc",
     ]
 
+    # Required for base/stack_trace_win.cc to symbolize correctly.
+    data += [ "$root_build_dir/dbghelp.dll" ]
+
+    if (is_component_build) {
+      # Copy the VS runtime DLLs into the isolate so that they don't have to be
+      # preinstalled on the target machine. The debug runtimes have a "d" at
+      # the end.
+      if (is_debug) {
+        vcrt_suffix = "d"
+      } else {
+        vcrt_suffix = ""
+      }
+
+      # These runtime files are copied to the output directory by the
+      # vs_toolchain script that runs as part of toolchain configuration.
+      data += [
+        "$root_out_dir/msvcp120${vcrt_suffix}.dll",
+        "$root_out_dir/msvcr120${vcrt_suffix}.dll",
+      ]
+      if (is_asan) {
+        data += [ "//third_party/llvm-build/Release+Asserts/lib/clang/3.8.0/lib/windows/clang_rt.asan_dynamic-i386.dll" ]
+      }
+    }
+
     # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
     configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
@@ -762,18 +849,24 @@
       "setupapi.lib",
     ]
     all_dependent_configs = [ ":base_win_linker_flags" ]
-  } else if (!is_nacl) {
+  } else if (!is_nacl || is_nacl_nonsfi) {
     # Non-Windows.
     deps += [ "//third_party/libevent" ]
   }
 
   # Mac.
-  if (is_mac) {
+  if (is_mac || is_ios) {
+    # Common Desktop / iOS excludes
     sources -= [
       "native_library_posix.cc",
       "strings/sys_string_conversions_posix.cc",
       "threading/platform_thread_internal_posix.cc",
     ]
+
+    if (is_asan) {
+      # TODO(GYP) hook up asan on Mac. GYP has this extra dylib:
+      #data += [ "$root_out_dir/libclang_rt.asan_osx_dynamic.dylib" ]
+    }
   } else {
     # Non-Mac.
     sources -= [
@@ -786,6 +879,11 @@
 
   # Linux.
   if (is_linux) {
+    if (is_asan || is_lsan || is_msan || is_tsan) {
+      # For llvm-sanitizer.
+      data += [ "//third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6" ]
+    }
+
     # TODO(brettw) this will need to be parameterized at some point.
     linux_configs = []
     if (use_glib) {
@@ -818,6 +916,48 @@
     }
   }
 
+  # iOS
+  if (is_ios) {
+    set_sources_assignment_filter([])
+
+    sources += [
+      "atomicops_internals_mac.h",
+      "base_paths_mac.h",
+      "base_paths_mac.mm",
+      "file_version_info_mac.h",
+      "file_version_info_mac.mm",
+      "files/file_util_mac.mm",
+      "mac/bundle_locations.h",
+      "mac/bundle_locations.mm",
+      "mac/call_with_eh_frame.cc",
+      "mac/call_with_eh_frame.h",
+      "mac/foundation_util.h",
+      "mac/foundation_util.mm",
+      "mac/mac_logging.cc",
+      "mac/mac_logging.h",
+      "mac/mach_logging.cc",
+      "mac/mach_logging.h",
+      "mac/objc_property_releaser.h",
+      "mac/objc_property_releaser.mm",
+      "mac/scoped_mach_port.cc",
+      "mac/scoped_mach_port.h",
+      "mac/scoped_mach_vm.cc",
+      "mac/scoped_mach_vm.h",
+      "mac/scoped_nsautorelease_pool.h",
+      "mac/scoped_nsautorelease_pool.mm",
+      "mac/scoped_nsobject.h",
+      "mac/scoped_objc_class_swizzler.h",
+      "mac/scoped_objc_class_swizzler.mm",
+      "message_loop/message_pump_mac.h",
+      "message_loop/message_pump_mac.mm",
+      "strings/sys_string_conversions_mac.mm",
+      "threading/platform_thread_mac.mm",
+      "time/time_mac.cc",
+    ]
+
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
   if (!use_glib) {
     sources -= [
       "message_loop/message_pump_glib.cc",
@@ -825,9 +965,19 @@
     ]
   }
 
+  if (is_asan || is_lsan || is_msan || is_tsan) {
+    data += [ "//tools/valgrind/asan/" ]
+    if (is_win) {
+      data +=
+          [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer.exe" ]
+    } else {
+      data += [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer" ]
+    }
+  }
+
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
-  if (is_android && !is_debug) {
-    configs -= [ "//build/config/compiler:optimize" ]
+  if (!is_debug) {
+    configs -= [ "//build/config/compiler:default_optimization" ]
     configs += [ "//build/config/compiler:optimize_max" ]
   }
 
@@ -845,8 +995,8 @@
     "win/pe_image.h",
   ]
 
-  if (is_android && !is_debug) {
-    configs -= [ "//build/config/compiler:optimize" ]
+  if (!is_debug) {
+    configs -= [ "//build/config/compiler:default_optimization" ]
     configs += [ "//build/config/compiler:optimize_max" ]
   }
 }
@@ -873,6 +1023,8 @@
     "i18n/icu_string_conversions.h",
     "i18n/icu_util.cc",
     "i18n/icu_util.h",
+    "i18n/message_formatter.cc",
+    "i18n/message_formatter.h",
     "i18n/number_formatting.cc",
     "i18n/number_formatting.h",
     "i18n/rtl.cc",
@@ -892,14 +1044,16 @@
   ]
   defines = [ "BASE_I18N_IMPLEMENTATION" ]
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
+  public_deps = [
+    "//third_party/icu",
+  ]
   deps = [
     ":base",
     "//base/third_party/dynamic_annotations",
-    "//third_party/icu",
   ]
 
-  if (is_android && !is_debug) {
-    configs -= [ "//build/config/compiler:optimize" ]
+  if (!is_debug) {
+    configs -= [ "//build/config/compiler:default_optimization" ]
     configs += [ "//build/config/compiler:optimize_max" ]
   }
 
@@ -907,7 +1061,7 @@
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 }
 
-if (is_win || (is_linux && !is_chromeos)) {
+if (is_ios || is_android || is_win || (is_linux && !is_chromeos)) {
   # TODO(GYP): Figure out which of these work and are needed on other platforms.
   test("base_perftests") {
     sources = [
@@ -920,8 +1074,8 @@
       ":base",
       "//base/test:test_support",
       "//base/test:test_support_perf",
-      "//testing/perf",
       "//testing/gtest",
+      "//testing/perf",
     ]
 
     if (is_android) {
@@ -949,6 +1103,7 @@
       ]
       deps = [
         ":base",
+        "//build/config/sanitizers:deps",
         "//third_party/icu:icuuc",
       ]
     }
@@ -959,6 +1114,7 @@
       ]
       deps = [
         ":base",
+        "//build/config/sanitizers:deps",
       ]
     }
   }
@@ -966,23 +1122,18 @@
 
 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",
@@ -1001,8 +1152,17 @@
     "prefs/scoped_user_pref_update.h",
     "prefs/value_map_pref_store.cc",
     "prefs/value_map_pref_store.h",
-    "prefs/writeable_pref_store.h",
   ]
+  if (!is_ios) {
+    sources += [
+      "prefs/base_prefs_export.h",
+      "prefs/persistent_pref_store.h",
+      "prefs/pref_filter.h",
+      "prefs/pref_notifier.h",
+      "prefs/pref_observer.h",
+      "prefs/writeable_pref_store.h",
+    ]
+  }
 
   defines = [ "BASE_PREFS_IMPLEMENTATION" ]
 
@@ -1010,8 +1170,8 @@
     ":base",
   ]
 
-  if (is_android && !is_debug) {
-    configs -= [ "//build/config/compiler:optimize" ]
+  if (!is_debug) {
+    configs -= [ "//build/config/compiler:default_optimization" ]
     configs += [ "//build/config/compiler:optimize_max" ]
   }
 }
@@ -1068,7 +1228,31 @@
       "cfgmgr32.lib",
       "shell32.lib",
     ]
+    deps = [
+      "//build/config/sanitizers:deps",
+    ]
   }
+
+  if (target_cpu == "x64") {
+    # Must be a shared library so that it can be unloaded during testing.
+    shared_library("base_profiler_test_support_library") {
+      sources = [
+        "profiler/test_support_library.cc",
+      ]
+      deps = [
+        "//build/config/sanitizers:deps",
+      ]
+    }
+  }
+}
+
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("base_unittests_run") {
+  testonly = true
+  deps = [
+    ":base_unittests",
+  ]
 }
 
 test("base_unittests") {
@@ -1082,11 +1266,11 @@
     "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",
+    "base64url_unittest.cc",
     "big_endian_unittest.cc",
     "bind_unittest.cc",
     "bind_unittest.nc",
@@ -1098,7 +1282,6 @@
     "callback_unittest.cc",
     "callback_unittest.nc",
     "cancelable_callback_unittest.cc",
-    "chromeos/memory_pressure_monitor_unittest.cc",
     "command_line_unittest.cc",
     "containers/adapters_unittest.cc",
     "containers/hash_tables_unittest.cc",
@@ -1125,6 +1308,7 @@
     "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",
@@ -1134,6 +1318,7 @@
     "i18n/char_iterator_unittest.cc",
     "i18n/file_util_icu_unittest.cc",
     "i18n/icu_string_conversions_unittest.cc",
+    "i18n/message_formatter_unittest.cc",
     "i18n/number_formatting_unittest.cc",
     "i18n/rtl_unittest.cc",
     "i18n/streaming_utf8_validator_unittest.cc",
@@ -1152,6 +1337,7 @@
     "lazy_instance_unittest.cc",
     "logging_unittest.cc",
     "mac/bind_objc_block_unittest.mm",
+    "mac/call_with_eh_frame_unittest.mm",
     "mac/dispatch_source_mach_unittest.cc",
     "mac/foundation_util_unittest.mm",
     "mac/libdispatch_task_runner_unittest.cc",
@@ -1164,17 +1350,19 @@
     "memory/aligned_memory_unittest.cc",
     "memory/discardable_shared_memory_unittest.cc",
     "memory/linked_ptr_unittest.cc",
+    "memory/memory_pressure_monitor_chromeos_unittest.cc",
+    "memory/memory_pressure_monitor_win_unittest.cc",
     "memory/ref_counted_memory_unittest.cc",
     "memory/ref_counted_unittest.cc",
     "memory/scoped_ptr_unittest.cc",
     "memory/scoped_ptr_unittest.nc",
     "memory/scoped_vector_unittest.cc",
+    "memory/shared_memory_mac_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_task_runner_unittest.cc",
     "message_loop/message_loop_unittest.cc",
     "message_loop/message_pump_glib_unittest.cc",
     "message_loop/message_pump_io_ios_unittest.cc",
@@ -1182,13 +1370,15 @@
     "metrics/field_trial_unittest.cc",
     "metrics/histogram_base_unittest.cc",
     "metrics/histogram_delta_serialization_unittest.cc",
+    "metrics/histogram_macros_unittest.cc",
     "metrics/histogram_snapshot_manager_unittest.cc",
     "metrics/histogram_unittest.cc",
+    "metrics/metrics_hashes_unittest.cc",
     "metrics/sample_map_unittest.cc",
     "metrics/sample_vector_unittest.cc",
     "metrics/sparse_histogram_unittest.cc",
     "metrics/statistics_recorder_unittest.cc",
-    "move_unittest.cc",
+    "native_library_unittest.cc",
     "numerics/safe_numerics_unittest.cc",
     "observer_list_unittest.cc",
     "os_compat_android_unittest.cc",
@@ -1214,7 +1404,6 @@
     "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",
@@ -1226,6 +1415,7 @@
     "sha1_unittest.cc",
     "stl_util_unittest.cc",
     "strings/nullable_string16_unittest.cc",
+    "strings/pattern_unittest.cc",
     "strings/safe_sprintf_unittest.cc",
     "strings/string16_unittest.cc",
     "strings/string_number_conversions_unittest.cc",
@@ -1251,14 +1441,16 @@
     "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/icu_test_util.cc",
+    "test/icu_test_util.h",
+    "test/test_pending_task_unittest.cc",
     "test/test_reg_util_win_unittest.cc",
     "test/trace_event_analyzer_unittest.cc",
     "test/user_action_tester_unittest.cc",
     "threading/non_thread_safe_unittest.cc",
     "threading/platform_thread_unittest.cc",
+    "threading/sequenced_task_runner_handle_unittest.cc",
     "threading/sequenced_worker_pool_unittest.cc",
     "threading/simple_thread_unittest.cc",
     "threading/thread_checker_unittest.cc",
@@ -1289,13 +1481,13 @@
     "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_handle_unittest.cc",
     "win/scoped_process_information_unittest.cc",
     "win/scoped_variant_unittest.cc",
     "win/shortcut_unittest.cc",
@@ -1320,6 +1512,10 @@
     "//third_party/icu",
   ]
 
+  data = [
+    "test/data/",
+  ]
+
   # Allow more direct string conversions on platforms with native utf8
   # strings
   if (is_mac || is_ios || is_chromeos) {
@@ -1327,19 +1523,25 @@
   }
 
   if (is_android) {
-    apk_deps = [
+    deps += [
       ":base_java",
       ":base_java_unittest_support",
     ]
+
+    # TODO(brettw) I think this should not be here, we should not be using
+    # isolate files.
+    isolate_file = "base_unittests.isolate"
   }
 
   if (is_ios) {
     sources -= [
+      "files/file_path_watcher_unittest.cc",
+      "memory/discardable_shared_memory_unittest.cc",
+      "memory/shared_memory_unittest.cc",
       "process/memory_unittest.cc",
-      "process/memory_unittest_mac.h",
-      "process/memory_unittest_mac.mm",
       "process/process_unittest.cc",
       "process/process_util_unittest.cc",
+      "sync_socket_unittest.cc",
     ]
 
     # Pull in specific Mac files for iOS (which have been filtered out by file
@@ -1350,7 +1552,7 @@
       "mac/foundation_util_unittest.mm",
       "mac/objc_property_releaser_unittest.mm",
       "mac/scoped_nsobject_unittest.mm",
-      "sys_string_conversions_mac_unittest.mm",
+      "strings/sys_string_conversions_mac_unittest.mm",
     ]
     set_sources_assignment_filter(sources_assignment_filter)
 
@@ -1371,7 +1573,7 @@
     sources -= [ "message_loop/message_pump_glib_unittest.cc" ]
   }
 
-  if (is_posix || is_ios) {
+  if (is_posix && !is_ios) {
     sources += [ "message_loop/message_pump_libevent_unittest.cc" ]
     deps += [ "//third_party/libevent" ]
   }
@@ -1383,8 +1585,22 @@
     set_sources_assignment_filter(sources_assignment_filter)
   }
 
+  if (is_win && target_cpu == "x64") {
+    sources += [ "profiler/win32_stack_frame_unwinder_unittest.cc" ]
+    deps += [ ":base_profiler_test_support_library" ]
+  }
+
   # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  # Symbols for crashes when running tests on swarming.
+  if (symbol_level > 0) {
+    if (is_win) {
+      data += [ "$root_out_dir/base_unittests.exe.pdb" ]
+    } else if (is_mac) {
+      data += [ "$root_out_dir/base_unittests.dSYM/" ]
+    }
+  }
 }
 
 if (is_android) {
@@ -1392,10 +1608,12 @@
   generate_jni("base_jni_headers") {
     sources = [
       "android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java",
+      "android/java/src/org/chromium/base/ApkAssets.java",
       "android/java/src/org/chromium/base/ApplicationStatus.java",
       "android/java/src/org/chromium/base/BuildInfo.java",
       "android/java/src/org/chromium/base/CommandLine.java",
       "android/java/src/org/chromium/base/ContentUriUtils.java",
+      "android/java/src/org/chromium/base/ContextUtils.java",
       "android/java/src/org/chromium/base/CpuFeatures.java",
       "android/java/src/org/chromium/base/EventLog.java",
       "android/java/src/org/chromium/base/FieldTrialList.java",
@@ -1416,7 +1634,7 @@
       "android/java/src/org/chromium/base/metrics/RecordUserAction.java",
     ]
 
-    deps = [
+    public_deps = [
       ":android_runtime_jni_headers",
     ]
 
@@ -1433,10 +1651,12 @@
   android_library("base_java") {
     srcjar_deps = [
       ":base_android_java_enums_srcjar",
+      ":base_multidex_gen",
       ":base_native_libraries_gen",
     ]
 
     deps = [
+      "//third_party/android_tools:android_support_multidex_java",
       "//third_party/jsr-305:jsr_305_javalib",
     ]
 
@@ -1468,12 +1688,29 @@
     DEPRECATED_java_in_dir = "test/android/javatests/src"
   }
 
+  # TODO(jbudorick): Remove this once we roll to robolectric 3.0 and pull
+  # in the multidex shadow library. crbug.com/522043
+  # GYP: //base.gyp:base_junit_test_support
+  java_library("base_junit_test_support") {
+    testonly = true
+    java_files = [ "test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java" ]
+    deps = [
+      "//third_party/android_tools:android_support_multidex_java",
+      "//third_party/robolectric:android-all-4.3_r2-robolectric-0",
+      "//third_party/robolectric:robolectric_java",
+    ]
+  }
+
   # GYP: //base.gyp:base_junit_tests
   junit_binary("base_junit_tests") {
-    java_files = [ "android/junit/src/org/chromium/base/LogTest.java" ]
+    java_files = [
+      "android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java",
+      "android/junit/src/org/chromium/base/LogTest.java",
+    ]
     deps = [
       ":base_java",
       ":base_java_test_support",
+      ":base_junit_test_support",
     ]
   }
 
@@ -1488,12 +1725,17 @@
       "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_multidex_gen
+  java_cpp_template("base_multidex_gen") {
+    sources = [
+      "android/java/templates/ChromiumMultiDex.template",
     ]
+    if (is_debug) {
+      defines = [ "MULTIDEX_CONFIGURATION_Debug" ]
+    }
+    package_name = "org/chromium/base/multidex"
   }
 
   # GYP: //base/base.gyp:base_native_libraries_gen
diff --git a/base/DEPS b/base/DEPS
index c632e35..6d91c8d 100644
--- a/base/DEPS
+++ b/base/DEPS
@@ -4,6 +4,7 @@
   "+third_party/apple_apsl",
   "+third_party/libevent",
   "+third_party/dmg_fp",
+  "+third_party/lss",
   "+third_party/mach_override",
   "+third_party/modp_b64",
   "+third_party/tcmalloc",
diff --git a/base/OWNERS b/base/OWNERS
index 9890491..4d4a239 100644
--- a/base/OWNERS
+++ b/base/OWNERS
@@ -1,13 +1,8 @@
 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.
 #
@@ -21,11 +16,17 @@
 # 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 *.isolate=tandrii@chromium.org
+per-file *.isolate=vadimsh@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*=torne@chromium.org
 per-file *android*=yfriedman@chromium.org
+
+# For FeatureList API:
+per-file feature_list*=asvitkine@chromium.org
+per-file feature_list*=isherman@chromium.org
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index a07a356..ad781f8 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -4,14 +4,47 @@
 
 import("//build/config/allocator.gni")
 
+declare_args() {
+  # Provide a way to force disable debugallocation in Debug builds,
+  # e.g. for profiling (it's more rare to profile Debug builds,
+  # but people sometimes need to do that).
+  enable_debugallocation = is_debug
+}
+
 # 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") {
+  public_deps = []
   if (use_allocator == "tcmalloc") {
-    deps = [
-      ":tcmalloc",
+    public_deps += [ ":tcmalloc" ]
+  }
+
+  # This condition expresses the win_use_allocator_shim in the GYP build.
+  if (is_win && !is_component_build) {
+    public_deps += [ ":allocator_shim" ]
+  }
+}
+
+# This config defines ALLOCATOR_SHIM in the same conditions that the allocator
+# shim will be used by the allocator target.
+#
+# TODO(brettw) this is only used in one place and is kind of mess, because it
+# assumes that the library using it will eventually be linked with
+# //base/allocator in the default way. Clean this up and delete this.
+config("allocator_shim_define") {
+  if (is_win && !is_component_build) {
+    defines = [ "ALLOCATOR_SHIM" ]
+  }
+}
+
+config("tcmalloc_flags") {
+  if (enable_debugallocation) {
+    defines = [
+      # Use debugallocation for Debug builds to catch problems early
+      # and cleanly, http://crbug.com/30715 .
+      "TCMALLOC_FOR_DEBUGALLOCATION",
     ]
   }
 }
@@ -28,16 +61,38 @@
     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 (!is_component_build) {
+    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,
+
+        # The environment file in the build directory. This is required because
+        # the Windows toolchain setup saves the VC paths and such so that
+        # running "mc.exe" will work with the configured toolchain. This file
+        # is in the root build dir.
+        "environment.$current_cpu",
+      ]
+    }
+
+    source_set("allocator_shim") {
+      sources = [
+        "allocator_shim_win.cc",
+      ]
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+
+      public_configs = [ ":nocmt" ]
+      deps = [
+        ":prep_libc",
+        "//base",
+      ]
+    }
   }
 }
 
@@ -52,7 +107,7 @@
     check_includes = false
 
     sources = [
-      # Generated for our configuration from tcmalloc"s build
+      # Generated for our configuration from tcmalloc's build
       # and checked in.
       "$tcmalloc_dir/src/config.h",
       "$tcmalloc_dir/src/config_android.h",
@@ -63,6 +118,17 @@
       "$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.
@@ -92,8 +158,6 @@
 
       # #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",
@@ -138,7 +202,6 @@
       "$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.
@@ -156,7 +219,10 @@
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
+    configs += [
+      "//build/config/compiler:no_chromium_code",
+      ":tcmalloc_flags",
+    ]
 
     deps = []
 
@@ -174,9 +240,6 @@
         "$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",
@@ -204,9 +267,6 @@
         "$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.
@@ -234,7 +294,7 @@
     # 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:default_optimization" ]
       configs += [ "//build/config/compiler:optimize_max" ]
     }
 
@@ -246,14 +306,14 @@
   }
 }  # !is_android
 
-source_set("allocator_extension_thunks") {
+source_set("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:default_optimization" ]
     configs += [ "//build/config/compiler:optimize_max" ]
   }
 }
diff --git a/base/allocator/OWNERS b/base/allocator/OWNERS
new file mode 100644
index 0000000..5d9997b
--- /dev/null
+++ b/base/allocator/OWNERS
@@ -0,0 +1,4 @@
+wfh@chromium.org
+
+# For changes to tcmalloc it is advisable to ask jar@chromium.org
+# before proceeding.
diff --git a/base/allocator/README b/base/allocator/README
index ec8a707..8a5595f 100644
--- a/base/allocator/README
+++ b/base/allocator/README
@@ -7,7 +7,6 @@
    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
@@ -23,11 +22,10 @@
 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 tcmalloc library originates outside of Chromium and exists in
+../../third_party/tcmalloc (currently, the actual location is defined in the
+allocator.gyp file). The third party sources use a vendor-branch SCM pattern to
+track Chromium-specific changes independently from upstream changes.
 
 The general intent is to push local changes upstream so that over
 time we no longer need any forked files.
@@ -54,6 +52,5 @@
 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
index d426c9c..ae93e9e 100644
--- a/base/allocator/allocator.gyp
+++ b/base/allocator/allocator.gyp
@@ -153,8 +153,6 @@
             '<(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',
@@ -296,20 +294,7 @@
             '../..',
           ],
         }],
-        ['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"', {
+        ['OS=="win" and component!="shared_library"', {
           'dependencies': [
             'libcmt',
           ],
@@ -382,22 +367,10 @@
       '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"', {
+    ['OS=="win" and component!="shared_library"', {
       'targets': [
         {
           'target_name': 'libcmt',
@@ -462,93 +435,6 @@
         },
       ],
     }],
-    ['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': [
          {
diff --git a/base/allocator/allocator_extension.cc b/base/allocator/allocator_extension.cc
index 83e460a..75918d1 100644
--- a/base/allocator/allocator_extension.cc
+++ b/base/allocator/allocator_extension.cc
@@ -9,22 +9,6 @@
 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();
@@ -32,19 +16,6 @@
     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(),
@@ -52,5 +23,12 @@
   thunks::SetReleaseFreeMemoryFunction(release_free_memory_function);
 }
 
+void SetGetNumericPropertyFunction(
+    thunks::GetNumericPropertyFunction get_numeric_property_function) {
+  DCHECK_EQ(thunks::GetGetNumericPropertyFunction(),
+            reinterpret_cast<thunks::GetNumericPropertyFunction>(NULL));
+  thunks::SetGetNumericPropertyFunction(get_numeric_property_function);
+}
+
 }  // namespace allocator
 }  // namespace base
diff --git a/base/allocator/allocator_extension.h b/base/allocator/allocator_extension.h
index e65822b..e2f1e70 100644
--- a/base/allocator/allocator_extension.h
+++ b/base/allocator/allocator_extension.h
@@ -14,28 +14,10 @@
 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
@@ -44,15 +26,13 @@
 // 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);
 
+BASE_EXPORT void SetGetNumericPropertyFunction(
+    thunks::GetNumericPropertyFunction get_numeric_property_function);
+
 }  // namespace allocator
 }  // namespace base
 
diff --git a/base/allocator/allocator_extension_thunks.cc b/base/allocator/allocator_extension_thunks.cc
index e4024fb..8dedb98 100644
--- a/base/allocator/allocator_extension_thunks.cc
+++ b/base/allocator/allocator_extension_thunks.cc
@@ -17,26 +17,8 @@
 // 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;
-}
+static GetNumericPropertyFunction g_get_numeric_property_function = NULL;
 
 void SetReleaseFreeMemoryFunction(
     ReleaseFreeMemoryFunction release_free_memory_function) {
@@ -47,6 +29,15 @@
   return g_release_free_memory_function;
 }
 
+void SetGetNumericPropertyFunction(
+    GetNumericPropertyFunction get_numeric_property_function) {
+  g_get_numeric_property_function = get_numeric_property_function;
+}
+
+GetNumericPropertyFunction GetGetNumericPropertyFunction() {
+  return g_get_numeric_property_function;
+}
+
 }  // namespace thunks
 }  // namespace allocator
 }  // namespace base
diff --git a/base/allocator/allocator_extension_thunks.h b/base/allocator/allocator_extension_thunks.h
index 4e5027b..c316767 100644
--- a/base/allocator/allocator_extension_thunks.h
+++ b/base/allocator/allocator_extension_thunks.h
@@ -15,20 +15,16 @@
 // 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();
 
+typedef bool (*GetNumericPropertyFunction)(const char* name, size_t* value);
+void SetGetNumericPropertyFunction(
+    GetNumericPropertyFunction get_numeric_property_function);
+GetNumericPropertyFunction GetGetNumericPropertyFunction();
+
 }  // namespace thunks
 }  // namespace allocator
 }  // namespace base
diff --git a/base/allocator/allocator_shim_win.cc b/base/allocator/allocator_shim_win.cc
index a1473e5..2a933ee 100644
--- a/base/allocator/allocator_shim_win.cc
+++ b/base/allocator/allocator_shim_win.cc
@@ -172,6 +172,9 @@
   return ptr;
 }
 
+// Symbol to allow weak linkage to win_heap_malloc from memory_win.cc.
+void* (*malloc_unchecked)(size_t) = &win_heap_malloc;
+
 // free.c
 void free(void* p) {
   win_heap_free(p);
diff --git a/base/allocator/prep_libc.py b/base/allocator/prep_libc.py
index 079297b..a88d3bd 100755
--- a/base/allocator/prep_libc.py
+++ b/base/allocator/prep_libc.py
@@ -7,24 +7,34 @@
 # This script takes libcmt.lib for VS2013 and removes the allocation related
 # functions from it.
 #
-# Usage: prep_libc.py <VCLibDir> <OutputDir> <arch>
+# Usage: prep_libc.py <VCLibDir> <OutputDir> <arch> [<environment_file>]
 #
 # 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.
+#
+# If the environment_file argument is set, the environment variables in the
+# given file will be used to execute the VC tools. This file is in the same
+# format as the environment block passed to CreateProcess.
 
 import os
 import shutil
 import subprocess
 import sys
 
-def run(command):
+def run(command, env_dict):
   """Run |command|.  If any lines that match an error condition then
-      terminate."""
+      terminate.
+
+  The env_dict, will be used for the environment. None can be used to get the
+  default environment."""
   error = 'cannot find member object'
+  # Need shell=True to search the path in env_dict for the executable.
   popen = subprocess.Popen(
-      command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+      command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True,
+      env=env_dict)
   out, _ = popen.communicate()
   for line in out.splitlines():
     print line
@@ -41,6 +51,13 @@
     bindir = 'SELF_64_amd64'
     objdir = 'amd64'
     vs_install_dir = os.path.join(vs_install_dir, 'amd64')
+
+  if len(sys.argv) == 5:
+    env_pairs = open(sys.argv[4]).read()[:-2].split('\0')
+    env_dict = dict([item.split('=', 1) for item in env_pairs])
+  else:
+    env_dict = None  # Use the default environment.
+
   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'),
@@ -57,11 +74,11 @@
   for obj in cobjfiles:
     cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
            (cvspath, obj, output_lib))
-    run(cmd)
+    run(cmd, env_dict)
   for obj in cppobjfiles:
     cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
            (cppvspath, obj, output_lib))
-    run(cmd)
+    run(cmd, env_dict)
 
 if __name__ == "__main__":
   sys.exit(main())
diff --git a/base/allocator/type_profiler.cc b/base/allocator/type_profiler.cc
deleted file mode 100644
index 635fbcf..0000000
--- a/base/allocator/type_profiler.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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
deleted file mode 100644
index 86b5711..0000000
--- a/base/allocator/type_profiler.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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
deleted file mode 100644
index 6be7984..0000000
--- a/base/allocator/type_profiler_control.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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
deleted file mode 100644
index 17cf5b6..0000000
--- a/base/allocator/type_profiler_control.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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
deleted file mode 100644
index 514ec16..0000000
--- a/base/allocator/type_profiler_map_unittest.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2014 The Chromium Authors. 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
deleted file mode 100644
index e5e10e0..0000000
--- a/base/allocator/type_profiler_tcmalloc.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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
deleted file mode 100644
index ac55995..0000000
--- a/base/allocator/type_profiler_tcmalloc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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
deleted file mode 100644
index 3d7369c..0000000
--- a/base/allocator/type_profiler_unittest.cc
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2014 The Chromium Authors. 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/android/OWNERS b/base/android/OWNERS
index 778fb75..077efd6 100644
--- a/base/android/OWNERS
+++ b/base/android/OWNERS
@@ -1,3 +1,4 @@
 nyquist@chromium.org
 rmcilroy@chromium.org
+torne@chromium.org
 yfriedman@chromium.org
diff --git a/base/android/animation_frame_time_histogram.cc b/base/android/animation_frame_time_histogram.cc
index 0d79619..2cf7516 100644
--- a/base/android/animation_frame_time_histogram.cc
+++ b/base/android/animation_frame_time_histogram.cc
@@ -10,9 +10,9 @@
 
 // static
 void SaveHistogram(JNIEnv* env,
-                   jobject jcaller,
-                   jstring j_histogram_name,
-                   jlongArray j_frame_times_ms,
+                   const JavaParamRef<jobject>& jcaller,
+                   const JavaParamRef<jstring>& j_histogram_name,
+                   const JavaParamRef<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(
diff --git a/base/android/apk_assets.cc b/base/android/apk_assets.cc
new file mode 100644
index 0000000..5319e73
--- /dev/null
+++ b/base/android/apk_assets.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 <jni.h>
+
+#include "base/android/apk_assets.h"
+
+#include "base/android/context_utils.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "jni/ApkAssets_jni.h"
+
+namespace base {
+namespace android {
+
+bool RegisterApkAssets(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+int OpenApkAsset(const std::string& file_path,
+                 base::MemoryMappedFile::Region* region) {
+  // The AAssetManager API of the NDK is does not expose a method for accessing
+  // raw resources :(.
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jlongArray> jarr = Java_ApkAssets_open(
+      env,
+      base::android::GetApplicationContext(),
+      base::android::ConvertUTF8ToJavaString(env, file_path).obj());
+  std::vector<jlong> results;
+  base::android::JavaLongArrayToLongVector(env, jarr.obj(), &results);
+  CHECK_EQ(3U, results.size());
+  int fd = static_cast<int>(results[0]);
+  region->offset = results[1];
+  region->size = results[2];
+  return fd;
+}
+
+bool RegisterApkAssetWithGlobalDescriptors(base::GlobalDescriptors::Key key,
+                                           const std::string& file_path) {
+  base::MemoryMappedFile::Region region =
+      base::MemoryMappedFile::Region::kWholeFile;
+  int asset_fd = OpenApkAsset(file_path, &region);
+  if (asset_fd != -1) {
+    base::GlobalDescriptors::GetInstance()->Set(key, asset_fd, region);
+  }
+  return asset_fd != -1;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/apk_assets.h b/base/android/apk_assets.h
new file mode 100644
index 0000000..6eb5da3
--- /dev/null
+++ b/base/android/apk_assets.h
@@ -0,0 +1,40 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_APK_ASSETS_H_
+#define BASE_ANDROID_APK_ASSETS_H_
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/posix/global_descriptors.h"
+
+namespace base {
+namespace android {
+
+bool RegisterApkAssets(JNIEnv* env);
+
+// Opens an asset (e.g. a .pak file) from the apk.
+// Can be used from renderer process.
+// Fails if the asset is not stored uncompressed within the .apk.
+// Returns: The File Descriptor of the asset, or -1 upon failure.
+// Input arguments:
+// - |file_path|: Path to file within .apk. e.g.: assets/foo.pak
+// Output arguments:
+// - |region|: size & offset (in bytes) within the .apk of the asset.
+BASE_EXPORT int OpenApkAsset(
+    const std::string& file_path,
+    base::MemoryMappedFile::Region* region);
+
+// Registers an uncompressed asset from within the apk with GlobalDescriptors.
+// Returns: true in case of success, false otherwise.
+BASE_EXPORT bool RegisterApkAssetWithGlobalDescriptors(
+    base::GlobalDescriptors::Key key,
+    const std::string& file_path);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_APK_ASSETS_H_
diff --git a/base/android/application_status_listener.cc b/base/android/application_status_listener.cc
index 02178c4..a139268 100644
--- a/base/android/application_status_listener.cc
+++ b/base/android/application_status_listener.cc
@@ -10,29 +10,30 @@
 #include "base/observer_list_threadsafe.h"
 #include "jni/ApplicationStatus_jni.h"
 
+namespace base {
+namespace android {
+
 namespace {
+
 struct LeakyLazyObserverListTraits :
     base::internal::LeakyLazyInstanceTraits<
-        ObserverListThreadSafe<base::android::ApplicationStatusListener> > {
-  static ObserverListThreadSafe<base::android::ApplicationStatusListener>*
+        ObserverListThreadSafe<ApplicationStatusListener> > {
+  static ObserverListThreadSafe<ApplicationStatusListener>*
       New(void* instance) {
-    ObserverListThreadSafe<base::android::ApplicationStatusListener>* ret =
+    ObserverListThreadSafe<ApplicationStatusListener>* ret =
         base::internal::LeakyLazyInstanceTraits<ObserverListThreadSafe<
-            base::android::ApplicationStatusListener> >::New(instance);
+            ApplicationStatusListener>>::New(instance);
     // Leaky.
     ret->AddRef();
     return ret;
   }
 };
 
-base::LazyInstance<ObserverListThreadSafe<
-    base::android::ApplicationStatusListener>,
-        LeakyLazyObserverListTraits> g_observers = LAZY_INSTANCE_INITIALIZER;
+LazyInstance<ObserverListThreadSafe<ApplicationStatusListener>,
+             LeakyLazyObserverListTraits> g_observers =
+    LAZY_INSTANCE_INITIALIZER;
 
-} // namespace
-
-namespace base {
-namespace android {
+}  // namespace
 
 ApplicationStatusListener::ApplicationStatusListener(
     const ApplicationStatusListener::ApplicationStateChangeCallback& callback)
@@ -41,7 +42,7 @@
   g_observers.Get().AddObserver(this);
 
   Java_ApplicationStatus_registerThreadSafeNativeApplicationStateListener(
-      base::android::AttachCurrentThread());
+      AttachCurrentThread());
 }
 
 ApplicationStatusListener::~ApplicationStatusListener() {
@@ -64,8 +65,14 @@
                            state);
 }
 
+// static
+ApplicationState ApplicationStatusListener::GetState() {
+  return static_cast<ApplicationState>(
+      Java_ApplicationStatus_getStateForApplication(AttachCurrentThread()));
+}
+
 static void OnApplicationStateChange(JNIEnv* env,
-                                     jclass clazz,
+                                     const JavaParamRef<jclass>& clazz,
                                      jint new_state) {
   ApplicationState application_state = static_cast<ApplicationState>(new_state);
   ApplicationStatusListener::NotifyApplicationStateChange(application_state);
diff --git a/base/android/application_status_listener.h b/base/android/application_status_listener.h
index 30048b2..866ec8b 100644
--- a/base/android/application_status_listener.h
+++ b/base/android/application_status_listener.h
@@ -27,6 +27,7 @@
 // A Java counterpart will be generated for this enum.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base
 enum ApplicationState {
+  APPLICATION_STATE_UNKNOWN = 0,
   APPLICATION_STATE_HAS_RUNNING_ACTIVITIES = 1,
   APPLICATION_STATE_HAS_PAUSED_ACTIVITIES = 2,
   APPLICATION_STATE_HAS_STOPPED_ACTIVITIES = 3,
@@ -73,6 +74,9 @@
   // Internal use only: must be public to be called from JNI and unit tests.
   static void NotifyApplicationStateChange(ApplicationState state);
 
+  // Expose jni call for ApplicationStatus.getStateForApplication.
+  static ApplicationState GetState();
+
  private:
   void Notify(ApplicationState state);
 
diff --git a/base/android/base_jni_registrar.cc b/base/android/base_jni_registrar.cc
index 43ba635..9ca3ce1 100644
--- a/base/android/base_jni_registrar.cc
+++ b/base/android/base_jni_registrar.cc
@@ -5,10 +5,12 @@
 #include "base/android/base_jni_registrar.h"
 
 #include "base/android/animation_frame_time_histogram.h"
+#include "base/android/apk_assets.h"
 #include "base/android/application_status_listener.h"
 #include "base/android/build_info.h"
 #include "base/android/command_line_android.h"
 #include "base/android/content_uri_utils.h"
+#include "base/android/context_utils.h"
 #include "base/android/cpu_features.h"
 #include "base/android/event_log.h"
 #include "base/android/field_trial_list.h"
@@ -38,11 +40,13 @@
 static RegistrationMethod kBaseRegisteredMethods[] = {
     {"AnimationFrameTimeHistogram",
      base::android::RegisterAnimationFrameTimeHistogram},
+    {"ApkAssets", base::android::RegisterApkAssets},
     {"ApplicationStatusListener",
      base::android::ApplicationStatusListener::RegisterBindings},
     {"BuildInfo", base::android::BuildInfo::RegisterBindings},
     {"CommandLine", base::android::RegisterCommandLine},
     {"ContentUriUtils", base::RegisterContentUriUtils},
+    {"ContextUtils", base::android::RegisterContextUtils},
     {"CpuFeatures", base::android::RegisterCpuFeatures},
     {"EventLog", base::android::RegisterEventLog},
     {"FieldTrialList", base::android::RegisterFieldTrialList},
diff --git a/base/android/build_info.cc b/base/android/build_info.cc
index 4d3cd55..2d3ef27 100644
--- a/base/android/build_info.cc
+++ b/base/android/build_info.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/android/context_utils.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
@@ -60,6 +61,8 @@
           env, GetApplicationContext()))),
       build_type_(StrDupJString(Java_BuildInfo_getBuildType(env))),
       sdk_int_(Java_BuildInfo_getSdkInt(env)),
+      has_language_apk_splits_(Java_BuildInfo_hasLanguageApkSplits(
+          env, GetApplicationContext())),
       java_exception_info_(NULL) {
 }
 
diff --git a/base/android/build_info.h b/base/android/build_info.h
index d6155b9..cc90df2 100644
--- a/base/android/build_info.h
+++ b/base/android/build_info.h
@@ -23,7 +23,9 @@
   SDK_VERSION_JELLY_BEAN_MR2 = 18,
   SDK_VERSION_KITKAT = 19,
   SDK_VERSION_KITKAT_WEAR = 20,
-  SDK_VERSION_LOLLIPOP = 21
+  SDK_VERSION_LOLLIPOP = 21,
+  SDK_VERSION_LOLLIPOP_MR1 = 22,
+  SDK_VERSION_MARSHMALLOW = 23
 };
 
 // BuildInfo is a singleton class that stores android build and device
@@ -95,6 +97,10 @@
     return sdk_int_;
   }
 
+  int has_language_apk_splits() const {
+    return has_language_apk_splits_;
+  }
+
   const char* java_exception_info() const {
     return java_exception_info_;
   }
@@ -126,6 +132,7 @@
   const char* const package_name_;
   const char* const build_type_;
   const int sdk_int_;
+  const bool has_language_apk_splits_;
   // This is set via set_java_exception_info, not at constructor time.
   const char* java_exception_info_;
 
diff --git a/base/android/command_line_android.cc b/base/android/command_line_android.cc
index 064450d..e196aed 100644
--- a/base/android/command_line_android.cc
+++ b/base/android/command_line_android.cc
@@ -31,40 +31,50 @@
 
 }  // namespace
 
-static void Reset(JNIEnv* env, jclass clazz) {
+static void Reset(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   CommandLine::Reset();
 }
 
-static jboolean HasSwitch(JNIEnv* env, jclass clazz, jstring jswitch) {
+static jboolean HasSwitch(JNIEnv* env,
+                          const JavaParamRef<jclass>& clazz,
+                          const JavaParamRef<jstring>& jswitch) {
   std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
   return CommandLine::ForCurrentProcess()->HasSwitch(switch_string);
 }
 
-static jstring GetSwitchValue(JNIEnv* env, jclass clazz, jstring jswitch) {
+static ScopedJavaLocalRef<jstring> GetSwitchValue(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<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();
+    return ScopedJavaLocalRef<jstring>();
+  return ConvertUTF8ToJavaString(env, value);
 }
 
-static void AppendSwitch(JNIEnv* env, jclass clazz, jstring jswitch) {
+static void AppendSwitch(JNIEnv* env,
+                         const JavaParamRef<jclass>& clazz,
+                         const JavaParamRef<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) {
+static void AppendSwitchWithValue(JNIEnv* env,
+                                  const JavaParamRef<jclass>& clazz,
+                                  const JavaParamRef<jstring>& jswitch,
+                                  const JavaParamRef<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) {
+static void AppendSwitchesAndArguments(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<jobjectArray>& array) {
   AppendJavaStringArrayToCommandLine(env, array, false);
 }
 
diff --git a/base/android/content_uri_utils.cc b/base/android/content_uri_utils.cc
index 0482fee..195598b 100644
--- a/base/android/content_uri_utils.cc
+++ b/base/android/content_uri_utils.cc
@@ -4,6 +4,7 @@
 
 #include "base/android/content_uri_utils.h"
 
+#include "base/android/context_utils.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "jni/ContentUriUtils_jni.h"
diff --git a/base/android/context_utils.cc b/base/android/context_utils.cc
new file mode 100644
index 0000000..5e10f21
--- /dev/null
+++ b/base/android/context_utils.cc
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/context_utils.h"
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/lazy_instance.h"
+#include "jni/ContextUtils_jni.h"
+
+using base::android::JavaRef;
+
+namespace base {
+namespace android {
+
+namespace {
+
+// 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;
+
+void SetNativeApplicationContext(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);
+}
+
+}  // namespace
+
+const jobject GetApplicationContext() {
+  DCHECK(!g_application_context.Get().is_null());
+  return g_application_context.Get().obj();
+}
+
+void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
+  SetNativeApplicationContext(env, context);
+  Java_ContextUtils_initJavaSideApplicationContext(env, context.obj());
+}
+
+static void InitNativeSideApplicationContext(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<jobject>& context) {
+  SetNativeApplicationContext(env, context);
+}
+
+bool RegisterContextUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/context_utils.h b/base/android/context_utils.h
new file mode 100644
index 0000000..67e6335
--- /dev/null
+++ b/base/android/context_utils.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_ANDROID_CONTEXT_UTILS_H_
+#define BASE_ANDROID_CONTEXT_UTILS_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// 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();
+
+// Initialize the global application context object.
+// Either this or the Java equivalent ContextUtils.initApplicationContext must
+// be called once during startup. JNI bindings must have been initialized, as
+// the context is stored on both sides.
+BASE_EXPORT void InitApplicationContext(
+    JNIEnv* env,
+    const base::android::JavaRef<jobject>& context);
+
+bool RegisterContextUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_CONTEXT_UTILS_H_
diff --git a/base/android/cpu_features.cc b/base/android/cpu_features.cc
index 6a18695..c139b78 100644
--- a/base/android/cpu_features.cc
+++ b/base/android/cpu_features.cc
@@ -10,11 +10,11 @@
 namespace base {
 namespace android {
 
-jint GetCoreCount(JNIEnv*, jclass) {
+jint GetCoreCount(JNIEnv*, const JavaParamRef<jclass>&) {
   return android_getCpuCount();
 }
 
-jlong GetCpuFeatures(JNIEnv*, jclass) {
+jlong GetCpuFeatures(JNIEnv*, const JavaParamRef<jclass>&) {
   return android_getCpuFeatures();
 }
 
diff --git a/base/android/cxa_demangle_stub.cc b/base/android/cxa_demangle_stub.cc
new file mode 100644
index 0000000..b0d2b87
--- /dev/null
+++ b/base/android/cxa_demangle_stub.cc
@@ -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.
+
+#include <unistd.h>
+
+// LLVM's demangler is large, and we have no need of it.  Overriding it with
+// our own stub version here stops a lot of code being pulled in from libc++.
+// More here:
+//   https://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp
+extern "C" char* __cxa_demangle(const char* mangled_name,
+                                char* buf,
+                                size_t* n,
+                                int* status) {
+  static const int kMemoryAllocFailure = -1;  // LLVM's memory_alloc_failure.
+  if (status)
+    *status = kMemoryAllocFailure;
+  return nullptr;
+}
diff --git a/base/android/field_trial_list.cc b/base/android/field_trial_list.cc
index 9cb38d2..9731a48 100644
--- a/base/android/field_trial_list.cc
+++ b/base/android/field_trial_list.cc
@@ -13,16 +13,18 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
 
-static jstring FindFullName(JNIEnv* env,
-                            jclass clazz,
-                            jstring jtrial_name) {
+static ScopedJavaLocalRef<jstring> FindFullName(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<jstring>& jtrial_name) {
   std::string trial_name(ConvertJavaStringToUTF8(env, jtrial_name));
   return ConvertUTF8ToJavaString(
-      env,
-      base::FieldTrialList::FindFullName(trial_name)).Release();
+      env, base::FieldTrialList::FindFullName(trial_name));
 }
 
-static jboolean TrialExists(JNIEnv* env, jclass clazz, jstring jtrial_name) {
+static jboolean TrialExists(JNIEnv* env,
+                            const JavaParamRef<jclass>& clazz,
+                            const JavaParamRef<jstring>& jtrial_name) {
   std::string trial_name(ConvertJavaStringToUTF8(env, jtrial_name));
   return base::FieldTrialList::TrialExists(trial_name);
 }
diff --git a/base/android/important_file_writer_android.cc b/base/android/important_file_writer_android.cc
index bcbd785..f324738 100644
--- a/base/android/important_file_writer_android.cc
+++ b/base/android/important_file_writer_android.cc
@@ -15,9 +15,9 @@
 namespace android {
 
 static jboolean WriteFileAtomically(JNIEnv* env,
-                                    jclass /* clazz */,
-                                    jstring file_name,
-                                    jbyteArray data) {
+                                    const JavaParamRef<jclass>& /* clazz */,
+                                    const JavaParamRef<jstring>& file_name,
+                                    const JavaParamRef<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;
diff --git a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
index ad5cdd8..1cd2acf 100644
--- a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
+++ b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
@@ -11,10 +11,13 @@
 import android.animation.TimeAnimator.TimeListener;
 import android.util.Log;
 
+import org.chromium.base.annotations.MainDex;
+
 /**
  * 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.
  */
+@MainDex
 public class AnimationFrameTimeHistogram {
     private static final String TAG = "AnimationFrameTimeHistogram";
     private static final int MAX_FRAME_TIME_NUM = 600; // 10 sec on 60 fps.
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index 76d7396..b94bed3 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -11,6 +11,8 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
@@ -19,6 +21,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.PowerManager;
+import android.os.Process;
 import android.provider.Settings;
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
@@ -337,9 +340,12 @@
      * @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.
+     * @param color Color of the activity. It must be a fully opaque color.
      */
     public static void setTaskDescription(Activity activity, String title, Bitmap icon, int color) {
+        // TaskDescription requires an opaque color.
+        assert Color.alpha(color) == 255;
+
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             ActivityManager.TaskDescription description =
                     new ActivityManager.TaskDescription(title, icon, color);
@@ -349,24 +355,6 @@
 
     /**
      * @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) {
@@ -404,4 +392,63 @@
             return res.getDrawableForDensity(id, density);
         }
     }
+
+    /**
+     * @see android.app.Activity#finishAfterTransition().
+     */
+    public static void finishAfterTransition(Activity activity) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            activity.finishAfterTransition();
+        } else {
+            activity.finish();
+        }
+    }
+
+    /**
+     * @see android.content.pm.PackageManager#getUserBadgedIcon(Drawable, android.os.UserHandle).
+     */
+    public static Drawable getUserBadgedIcon(Context context, int id) {
+        Drawable drawable = getDrawable(context.getResources(), id);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            PackageManager packageManager = context.getPackageManager();
+            drawable = packageManager.getUserBadgedIcon(drawable, Process.myUserHandle());
+        }
+        return drawable;
+    }
+
+    /**
+     * @see android.content.res.Resources#getColor(int id).
+     */
+    @SuppressWarnings("deprecation")
+    public static int getColor(Resources res, int id) throws NotFoundException {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return res.getColor(id, null);
+        } else {
+            return res.getColor(id);
+        }
+    }
+
+    /**
+     * @see android.content.res.Resources#getColorStateList(int id).
+     */
+    @SuppressWarnings("deprecation")
+    public static ColorStateList getColorStateList(Resources res, int id) throws NotFoundException {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return res.getColorStateList(id, null);
+        } else {
+            return res.getColorStateList(id);
+        }
+    }
+
+    /**
+     * @see android.widget.TextView#setTextAppearance(int id).
+     */
+    @SuppressWarnings("deprecation")
+    public static void setTextAppearance(TextView view, int id) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            view.setTextAppearance(id);
+        } else {
+            view.setTextAppearance(view.getContext(), id);
+        }
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/ApkAssets.java b/base/android/java/src/org/chromium/base/ApkAssets.java
new file mode 100644
index 0000000..e00be99
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ApkAssets.java
@@ -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.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.util.Log;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+import java.io.IOException;
+
+/**
+ * A utility class to retrieve references to uncompressed assets insides the apk. A reference is
+ * defined as tuple (file descriptor, offset, size) enabling direct mapping without deflation.
+ * This can be used even within the renderer process, since it just dup's the apk's fd.
+ */
+@JNINamespace("base::android")
+public class ApkAssets {
+    private static final String LOGTAG = "ApkAssets";
+
+    @CalledByNative
+    public static long[] open(Context context, String fileName) {
+        AssetFileDescriptor afd = null;
+        try {
+            AssetManager manager = context.getAssets();
+            afd = manager.openNonAssetFd(fileName);
+            return new long[] { afd.getParcelFileDescriptor().detachFd(),
+                                afd.getStartOffset(),
+                                afd.getLength() };
+        } catch (IOException e) {
+            Log.e(LOGTAG, "Error while loading asset " + fileName + ": " + e);
+            return new long[] {-1, -1, -1};
+        } finally {
+            try {
+                if (afd != null) {
+                    afd.close();
+                }
+            } catch (IOException e2) {
+                Log.e(LOGTAG, "Unable to close AssetFileDescriptor", e2);
+            }
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/ApplicationStatus.java b/base/android/java/src/org/chromium/base/ApplicationStatus.java
index 8c36b61..6895256 100644
--- a/base/android/java/src/org/chromium/base/ApplicationStatus.java
+++ b/base/android/java/src/org/chromium/base/ApplicationStatus.java
@@ -10,6 +10,10 @@
 import android.content.Context;
 import android.os.Bundle;
 
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.MainDex;
+
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -21,6 +25,7 @@
  * to register / unregister listeners for state changes.
  */
 @JNINamespace("base::android")
+@MainDex
 public class ApplicationStatus {
     private static class ActivityInfo {
         private int mStatus = ActivityState.DESTROYED;
@@ -304,6 +309,7 @@
     /**
      * @return The state of the application (see {@link ApplicationState}).
      */
+    @CalledByNative
     public static int getStateForApplication() {
         synchronized (sCachedApplicationStateLock) {
             if (sCachedApplicationState == null) {
@@ -388,6 +394,23 @@
     }
 
     /**
+     * Robolectric JUnit tests create a new application between each test, while all the context
+     * in static classes isn't reset. This function allows to reset the application status to avoid
+     * being in a dirty state.
+     */
+    public static void destroyForJUnitTests() {
+        sApplicationStateListeners.clear();
+        sGeneralActivityStateListeners.clear();
+        sActivityInfo.clear();
+        synchronized (sCachedApplicationStateLock) {
+            sCachedApplicationState = null;
+        }
+        sActivity = null;
+        sApplication = null;
+        sNativeApplicationStateListener = null;
+    }
+
+    /**
      * 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
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
index c87d02d..e4e6e20 100644
--- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
+++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
@@ -8,17 +8,32 @@
 import android.app.Application;
 import android.content.Context;
 import android.os.Bundle;
-import android.view.KeyEvent;
 import android.view.Window;
 
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
+import org.chromium.base.multidex.ChromiumMultiDex;
 
 /**
  * Basic application functionality that should be shared among all browser applications.
  */
 public class BaseChromiumApplication extends Application {
+
+    private static final String TAG = "cr.base";
+    private final boolean mShouldInitializeApplicationStatusTracking;
+
+    public BaseChromiumApplication() {
+        this(true);
+    }
+
+    protected BaseChromiumApplication(boolean shouldInitializeApplicationStatusTracking) {
+        mShouldInitializeApplicationStatusTracking = shouldInitializeApplicationStatusTracking;
+    }
+
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        ChromiumMultiDex.install(this);
+    }
+
     /**
      * Interface to be implemented by listeners for window focus events.
      */
@@ -34,96 +49,11 @@
     private ObserverList<WindowFocusChangedListener> mWindowFocusListeners =
             new ObserverList<WindowFocusChangedListener>();
 
-    /**
-     * Intercepts calls to an existing Window.Callback. Most invocations are passed on directly
-     * to the composed Window.Callback but enables intercepting/manipulating others.
-     *
-     * This is used to relay window focus changes throughout the app and remedy a bug in the
-     * appcompat library.
-     */
-    private class WindowCallbackProxy implements InvocationHandler {
-        private final Window.Callback mCallback;
-        private final Activity mActivity;
-
-        public WindowCallbackProxy(Activity activity, Window.Callback callback) {
-            mCallback = callback;
-            mActivity = activity;
-        }
-
-        @Override
-        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-            if (method.getName().equals("onWindowFocusChanged") && args.length == 1
-                    && args[0] instanceof Boolean) {
-                onWindowFocusChanged((boolean) args[0]);
-                return null;
-            } else if (method.getName().equals("dispatchKeyEvent") && args.length == 1
-                    && args[0] instanceof KeyEvent) {
-                return dispatchKeyEvent((KeyEvent) args[0]);
-            } else {
-                return method.invoke(mCallback, args);
-            }
-        }
-
-        public void onWindowFocusChanged(boolean hasFocus) {
-            mCallback.onWindowFocusChanged(hasFocus);
-
-            for (WindowFocusChangedListener listener : mWindowFocusListeners) {
-                listener.onWindowFocusChanged(mActivity, hasFocus);
-            }
-        }
-
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            // TODO(aurimas): remove this once AppCompatDelegateImpl no longer steals
-            // KEYCODE_MENU. (see b/20529185)
-            if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && mActivity.dispatchKeyEvent(event)) {
-                return true;
-            }
-            return mCallback.dispatchKeyEvent(event);
-        }
-    }
     @Override
     public void onCreate() {
         super.onCreate();
-        ApplicationStatus.initialize(this);
-        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
-            @Override
-            public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
-                Window.Callback callback = activity.getWindow().getCallback();
-                activity.getWindow().setCallback((Window.Callback) Proxy.newProxyInstance(
-                        Window.Callback.class.getClassLoader(), new Class[] {Window.Callback.class},
-                        new WindowCallbackProxy(activity, callback)));
-            }
 
-            @Override
-            public void onActivityDestroyed(Activity activity) {
-                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
-            }
-
-            @Override
-            public void onActivityPaused(Activity activity) {
-                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
-            }
-
-            @Override
-            public void onActivityResumed(Activity activity) {
-                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
-            }
-
-            @Override
-            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
-                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
-            }
-
-            @Override
-            public void onActivityStarted(Activity activity) {
-                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
-            }
-
-            @Override
-            public void onActivityStopped(Activity activity) {
-                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
-            }
-        });
+        if (mShouldInitializeApplicationStatusTracking) startTrackingApplicationStatus();
     }
 
     /**
@@ -152,5 +82,55 @@
     @VisibleForTesting
     public static void initCommandLine(Context context) {
         ((BaseChromiumApplication) context.getApplicationContext()).initCommandLine();
-    };
+    }
+
+    /** Register hooks and listeners to start tracking the application status. */
+    private void startTrackingApplicationStatus() {
+        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 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;
+            }
+        });
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
index 54f611d..3922154 100644
--- a/base/android/java/src/org/chromium/base/BuildInfo.java
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -4,6 +4,7 @@
 
 package org.chromium.base;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -12,6 +13,8 @@
 import android.os.Build;
 import android.util.Log;
 
+import org.chromium.base.annotations.CalledByNative;
+
 /**
  * BuildInfo is a utility class providing easy access to {@link PackageInfo}
  * information. This is primarly of use for accessesing package information
@@ -122,4 +125,26 @@
     public static int getSdkInt() {
         return Build.VERSION.SDK_INT;
     }
+
+    private static boolean isLanguageSplit(String splitName) {
+        // Names look like "config.XX".
+        return splitName.length() == 9 && splitName.startsWith("config.");
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    @CalledByNative
+    public static boolean hasLanguageApkSplits(Context context) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+            return false;
+        }
+        PackageInfo packageInfo = PackageUtils.getOwnPackageInfo(context);
+        if (packageInfo.splitNames != null) {
+            for (int i = 0; i < packageInfo.splitNames.length; ++i) {
+                if (isLanguageSplit(packageInfo.splitNames[i])) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/Callback.java b/base/android/java/src/org/chromium/base/Callback.java
new file mode 100644
index 0000000..771871f
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/Callback.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;
+
+/**
+ * A simple single-argument callback to handle the result of a computation.
+ *
+ * @param <T> The type of the computation's result.
+ */
+public interface Callback<T> {
+    /**
+     * Invoked with the result of a computation.
+     */
+    public void onResult(T result);
+}
diff --git a/base/android/java/src/org/chromium/base/CollectionUtil.java b/base/android/java/src/org/chromium/base/CollectionUtil.java
index 4a4c754..2672d65 100644
--- a/base/android/java/src/org/chromium/base/CollectionUtil.java
+++ b/base/android/java/src/org/chromium/base/CollectionUtil.java
@@ -31,6 +31,7 @@
         return list;
     }
 
+    @VisibleForTesting
     public static <E> ArrayList<E> newArrayList(Iterable<E> iterable) {
         ArrayList<E> list = new ArrayList<E>();
         for (E element : iterable) {
diff --git a/base/android/java/src/org/chromium/base/CommandLine.java b/base/android/java/src/org/chromium/base/CommandLine.java
index 9f54079..efef22a 100644
--- a/base/android/java/src/org/chromium/base/CommandLine.java
+++ b/base/android/java/src/org/chromium/base/CommandLine.java
@@ -7,6 +7,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import org.chromium.base.annotations.MainDex;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -16,15 +18,26 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 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.
+ * ContentShellApplication.COMMAND_LINE_FILE.
 **/
+@MainDex
 public abstract class CommandLine {
+    /**
+     * Allows classes who cache command line flags to be notified when those arguments are updated
+     * at runtime. This happens in tests.
+     */
+    public interface ResetListener {
+        /** Called when the command line arguments are reset. */
+        void onCommandLineReset();
+    }
+
     // Public abstract interface, implemented in derived classes.
     // All these methods reflect their native-side counterparts.
     /**
@@ -87,6 +100,7 @@
         return false;
     }
 
+    private static final List<ResetListener> sResetListeners = new ArrayList<>();
     private static final AtomicReference<CommandLine> sCommandLine =
             new AtomicReference<CommandLine>();
 
@@ -132,6 +146,20 @@
     @VisibleForTesting
     public static void reset() {
         setInstance(null);
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (ResetListener listener : sResetListeners) listener.onCommandLineReset();
+            }
+        });
+    }
+
+    public static void addResetListener(ResetListener listener) {
+        sResetListeners.add(listener);
+    }
+
+    public static void removeResetListener(ResetListener listener) {
+        sResetListeners.remove(listener);
     }
 
     /**
diff --git a/base/android/java/src/org/chromium/base/CommandLineInitUtil.java b/base/android/java/src/org/chromium/base/CommandLineInitUtil.java
new file mode 100644
index 0000000..6aa227c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CommandLineInitUtil.java
@@ -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.
+
+package org.chromium.base;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Build;
+import android.provider.Settings;
+
+import org.chromium.base.annotations.SuppressFBWarnings;
+
+import java.io.File;
+
+/**
+ * Provides implementation of command line initialization for Android.
+ */
+public final class CommandLineInitUtil {
+
+    private static final String TAG = "CommandLineInitUtil";
+
+    /**
+     * The location of the command line file needs to be in a protected
+     * directory so requires root access to be tweaked, i.e., no other app in a
+     * regular (non-rooted) device can change this file's contents.
+     * See below for debugging on a regular (non-rooted) device.
+     */
+    private static final String COMMAND_LINE_FILE_PATH = "/data/local";
+
+    /**
+     * This path (writable by the shell in regular non-rooted "user" builds) is used when:
+     * 1) The "debug app" is set to the application calling this.
+     * and
+     * 2) ADB is enabled.
+     *
+     */
+    private static final String COMMAND_LINE_FILE_PATH_DEBUG_APP = "/data/local/tmp";
+
+    private CommandLineInitUtil() {
+    }
+
+    /**
+     * Initializes the CommandLine class, pulling command line arguments from {@code fileName}.
+     * @param context  The {@link Context} to use to query whether or not this application is being
+     *                 debugged, and whether or not the publicly writable command line file should
+     *                 be used.
+     * @param fileName The name of the command line file to pull arguments from.
+     */
+    @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
+    public static void initCommandLine(Context context, String fileName) {
+        if (!CommandLine.isInitialized()) {
+            File commandLineFile = getAlternativeCommandLinePath(context, fileName);
+            if (commandLineFile == null) {
+                commandLineFile = new File(COMMAND_LINE_FILE_PATH, fileName);
+            }
+            CommandLine.initFromFile(commandLineFile.getPath());
+        }
+    }
+
+    /**
+     * Use an alternative path if adb is enabled and this is the debug app.
+     */
+    @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
+    private static File getAlternativeCommandLinePath(Context context, String fileName) {
+        File alternativeCommandLineFile =
+                new File(COMMAND_LINE_FILE_PATH_DEBUG_APP, fileName);
+        if (!alternativeCommandLineFile.exists()) return null;
+        try {
+            String debugApp = Build.VERSION.SDK_INT < 17
+                    ? getDebugAppPreJBMR1(context) : getDebugAppJBMR1(context);
+
+            if (debugApp != null
+                    && debugApp.equals(context.getApplicationContext().getPackageName())) {
+                Log.i(TAG, "Using alternative command line file in "
+                        + alternativeCommandLineFile.getPath());
+                return alternativeCommandLineFile;
+            }
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Unable to detect alternative command line file");
+        }
+
+        return null;
+    }
+
+    @SuppressLint("NewApi")
+    private static String getDebugAppJBMR1(Context context) {
+        boolean adbEnabled = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.ADB_ENABLED, 0) == 1;
+        if (adbEnabled) {
+            return Settings.Global.getString(context.getContentResolver(),
+                    Settings.Global.DEBUG_APP);
+        }
+        return null;
+    }
+
+    @SuppressWarnings("deprecation")
+    private static String getDebugAppPreJBMR1(Context context) {
+        boolean adbEnabled = Settings.System.getInt(context.getContentResolver(),
+                Settings.System.ADB_ENABLED, 0) == 1;
+        if (adbEnabled) {
+            return Settings.System.getString(context.getContentResolver(),
+                    Settings.System.DEBUG_APP);
+        }
+        return null;
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/ContentUriUtils.java b/base/android/java/src/org/chromium/base/ContentUriUtils.java
index ef527e1..528af8f 100644
--- a/base/android/java/src/org/chromium/base/ContentUriUtils.java
+++ b/base/android/java/src/org/chromium/base/ContentUriUtils.java
@@ -11,6 +11,8 @@
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
+import org.chromium.base.annotations.CalledByNative;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 
@@ -55,7 +57,7 @@
      *
      * @param context {@link Context} in interest
      * @param uriString the content URI to open
-     * @return file desciptor upon sucess, or -1 otherwise.
+     * @return file desciptor upon success, or -1 otherwise.
      */
     @CalledByNative
     public static int openContentUriForRead(Context context, String uriString) {
@@ -113,6 +115,8 @@
             Log.w(TAG, "Cannot open content uri: " + uriString, e);
         } catch (IllegalArgumentException e) {
             Log.w(TAG, "Unknown content uri: " + uriString, e);
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Unknown content uri: " + uriString, e);
         }
         return pfd;
     }
diff --git a/base/android/java/src/org/chromium/base/ContextUtils.java b/base/android/java/src/org/chromium/base/ContextUtils.java
new file mode 100644
index 0000000..51adcff
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ContextUtils.java
@@ -0,0 +1,64 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * This class provides Android Context utility methods.
+ */
+@JNINamespace("base::android")
+public class ContextUtils {
+    private static Context sApplicationContext;
+
+    /**
+     * Get the Android application context.
+     *
+     * Under normal circumstances there is only one application context in a process, so it's safe
+     * to treat this as a global. In WebView it's possible for more than one app using WebView to be
+     * running in a single process, but this mechanism is rarely used and this is not the only
+     * problem in that scenario, so we don't currently forbid using it as a global.
+     *
+     * Do not downcast the context returned by this method to Application (or any subclass). It may
+     * not be an Application object; it may be wrapped in a ContextWrapper. The only assumption you
+     * may make is that it is a Context whose lifetime is the same as the lifetime of the process.
+     */
+    public static Context getApplicationContext() {
+        assert sApplicationContext != null;
+        return sApplicationContext;
+    }
+
+    /**
+     * Initialize the Android application context.
+     *
+     * Either this or the native equivalent base::android::InitApplicationContext must be called
+     * once during startup. JNI bindings must have been initialized, as the context is stored on
+     * both sides.
+     */
+    public static void initApplicationContext(Context appContext) {
+        assert appContext != null;
+        assert sApplicationContext == null || sApplicationContext == appContext;
+        initJavaSideApplicationContext(appContext);
+        nativeInitNativeSideApplicationContext(appContext);
+    }
+
+    /**
+     * JUnit Robolectric tests run without native code; allow them to set just the Java-side
+     * context. Do not use in configurations that actually run on Android!
+     */
+    public static void initApplicationContextForJUnitTests(Context appContext) {
+        initJavaSideApplicationContext(appContext);
+    }
+
+    @CalledByNative
+    private static void initJavaSideApplicationContext(Context appContext) {
+        sApplicationContext = appContext;
+    }
+
+    private static native void nativeInitNativeSideApplicationContext(Context appContext);
+}
diff --git a/base/android/java/src/org/chromium/base/CpuFeatures.java b/base/android/java/src/org/chromium/base/CpuFeatures.java
index 0e8a7ab..ae4969c 100644
--- a/base/android/java/src/org/chromium/base/CpuFeatures.java
+++ b/base/android/java/src/org/chromium/base/CpuFeatures.java
@@ -4,6 +4,8 @@
 
 package org.chromium.base;
 
+import org.chromium.base.annotations.JNINamespace;
+
 // 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
diff --git a/base/android/java/src/org/chromium/base/EventLog.java b/base/android/java/src/org/chromium/base/EventLog.java
index 894de15..f889175 100644
--- a/base/android/java/src/org/chromium/base/EventLog.java
+++ b/base/android/java/src/org/chromium/base/EventLog.java
@@ -4,6 +4,9 @@
 
 package org.chromium.base;
 
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
 /**
  * A simple interface to Android's EventLog to be used by native code.
  */
diff --git a/base/android/java/src/org/chromium/base/FieldTrialList.java b/base/android/java/src/org/chromium/base/FieldTrialList.java
index 5fc9a1f..cfd7d5c 100644
--- a/base/android/java/src/org/chromium/base/FieldTrialList.java
+++ b/base/android/java/src/org/chromium/base/FieldTrialList.java
@@ -4,9 +4,12 @@
 
 package org.chromium.base;
 
+import org.chromium.base.annotations.MainDex;
+
 /**
  * Helper to get field trial information.
  */
+@MainDex
 public class FieldTrialList {
 
     private FieldTrialList() {}
diff --git a/base/android/java/src/org/chromium/base/FileUtils.java b/base/android/java/src/org/chromium/base/FileUtils.java
new file mode 100644
index 0000000..fbaec8c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/FileUtils.java
@@ -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.
+
+package org.chromium.base;
+
+import java.io.File;
+
+/**
+ * Helper methods for dealing with Files.
+ */
+public class FileUtils {
+    private static final String TAG = "FileUtils";
+
+    /**
+     * Delete the given File and (if it's a directory) everything within it.
+     */
+    public static void recursivelyDeleteFile(File currentFile) {
+        assert !ThreadUtils.runningOnUiThread();
+        if (currentFile.isDirectory()) {
+            File[] files = currentFile.listFiles();
+            if (files != null) {
+                for (File file : files) {
+                    recursivelyDeleteFile(file);
+                }
+            }
+        }
+
+        if (!currentFile.delete()) Log.e(TAG, "Failed to delete: " + currentFile);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java b/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java
index 3921cea..cbaf7f7 100644
--- a/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java
+++ b/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java
@@ -4,6 +4,8 @@
 
 package org.chromium.base;
 
+import org.chromium.base.annotations.JNINamespace;
+
 /**
  * This class provides an interface to the native class for writing
  * important data files without risking data loss.
diff --git a/base/android/java/src/org/chromium/base/JNIUtils.java b/base/android/java/src/org/chromium/base/JNIUtils.java
index 6f6cd54..f971b5e 100644
--- a/base/android/java/src/org/chromium/base/JNIUtils.java
+++ b/base/android/java/src/org/chromium/base/JNIUtils.java
@@ -4,9 +4,13 @@
 
 package org.chromium.base;
 
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.MainDex;
+
 /**
  * This class provides JNI-related methods to the native library.
  */
+@MainDex
 public class JNIUtils {
     /**
      * This returns a ClassLoader that is capable of loading Chromium Java code. Such a ClassLoader
diff --git a/base/android/java/src/org/chromium/base/JavaHandlerThread.java b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
index 3153a9b..cd05728 100644
--- a/base/android/java/src/org/chromium/base/JavaHandlerThread.java
+++ b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
@@ -9,6 +9,9 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
 /**
  * This class is an internal detail of the native counterpart.
  * It is instantiated and owned by the native object.
diff --git a/base/android/java/src/org/chromium/base/LocaleUtils.java b/base/android/java/src/org/chromium/base/LocaleUtils.java
index 82b2c8f..5c26e7a 100644
--- a/base/android/java/src/org/chromium/base/LocaleUtils.java
+++ b/base/android/java/src/org/chromium/base/LocaleUtils.java
@@ -4,6 +4,8 @@
 
 package org.chromium.base;
 
+import org.chromium.base.annotations.CalledByNative;
+
 import java.util.Locale;
 
 /**
@@ -17,12 +19,11 @@
     }
 
     /**
-     * @return the default locale, translating Android deprecated
-     * language codes into the modern ones used by Chromium.
+     * @return the string for the given locale, translating
+     * Android deprecated language codes into the modern ones
+     * used by Chromium.
      */
-    @CalledByNative
-    public static String getDefaultLocale() {
-        Locale locale = Locale.getDefault();
+    public static String getLocale(Locale locale) {
         String language = locale.getLanguage();
         String country = locale.getCountry();
 
@@ -41,6 +42,15 @@
     }
 
     /**
+     * @return the default locale, translating Android deprecated
+     * language codes into the modern ones used by Chromium.
+     */
+    @CalledByNative
+    public static String getDefaultLocale() {
+        return getLocale(Locale.getDefault());
+    }
+
+    /**
      * Get the default country code set during install.
      * @return country code.
      */
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
index 4c79a4d..7160f0e 100644
--- a/base/android/java/src/org/chromium/base/Log.java
+++ b/base/android/java/src/org/chromium/base/Log.java
@@ -4,9 +4,7 @@
 
 package org.chromium.base;
 
-import android.text.TextUtils;
-
-import org.chromium.base.annotations.NoSideEffects;
+import org.chromium.base.annotations.RemovableInRelease;
 
 import java.util.Locale;
 
@@ -19,38 +17,10 @@
  * 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.
+ * Usage documentation: {@code //docs/logging.md}.
  * </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;
 
@@ -69,6 +39,9 @@
     /** Convenience property, same as {@link android.util.Log#WARN}. */
     public static final int WARN = android.util.Log.WARN;
 
+    private static final String sTagPrefix = "cr_";
+    private static final String sDeprecatedTagPrefix = "cr.";
+
     private Log() {
         // Static only access
     }
@@ -83,6 +56,24 @@
     }
 
     /**
+     * Returns a normalized tag that will be in the form: "cr_foo". This function is called by the
+     * various Log overrides. If using {@link #isLoggable(String, int)}, you might want to call it
+     * to get the tag that will actually be used.
+     * @see #sTagPrefix
+     */
+    public static String normalizeTag(String tag) {
+        if (tag.startsWith(sTagPrefix)) return tag;
+
+        // TODO(dgn) simplify this once 'cr.' is out of the repo (http://crbug.com/533072)
+        int unprefixedTagStart = 0;
+        if (tag.startsWith(sDeprecatedTagPrefix)) {
+            unprefixedTagStart = sDeprecatedTagPrefix.length();
+        }
+
+        return sTagPrefix + tag.substring(unprefixedTagStart, tag.length());
+    }
+
+    /**
      * 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.
      */
@@ -91,25 +82,11 @@
     }
 
     /**
-     * Returns a full tag for the provided group tag. Full tags longer than 23 characters
-     * will cause a runtime exception.
+     * Convenience function, forwards to {@link android.util.Log#isLoggable(String, int)}.
      *
-     * @param groupTag {@code null} and empty string are allowed.
-     *
-     * @see android.util.Log#isLoggable(String, int)
-     * @throws IllegalArgumentException if the tag is too long.
+     * Note: Has no effect on whether logs are sent or not. Use a method with
+     * {@link RemovableInRelease} to log something in Debug builds only.
      */
-    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);
     }
@@ -119,68 +96,81 @@
      *
      * 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}.
+     * {@link RemovableInRelease}.
      *
-     * @param tag Used to identify the source of a log message. Should be created using
-     *            {@link #makeTag(String)}.
-     *
+     * @param tag Used to identify the source of a log message. Might be modified in the output
+     *            (see {@link #normalizeTag(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);
-            }
+        String message = formatLogWithStack(messageTemplate, args);
+        Throwable tr = getThrowableToLog(args);
+        if (tr != null) {
+            android.util.Log.v(normalizeTag(tag), message, tr);
+        } else {
+            android.util.Log.v(normalizeTag(tag), message);
         }
     }
 
-    /** Sends a {@link android.util.Log#VERBOSE} log message. 0 arg version. */
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 0 args version. */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void v(String tag, String message) {
         verbose(tag, message);
     }
 
     /** Sends a {@link android.util.Log#VERBOSE} log message. 1 arg version. */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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);
@@ -191,66 +181,79 @@
      *
      * 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}.
+     * {@link RemovableInRelease}.
      *
-     * @param tag Used to identify the source of a log message. Should be created using
-     *            {@link #makeTag(String)}.
-     *
+     * @param tag Used to identify the source of a log message. Might be modified in the output
+     *            (see {@link #normalizeTag(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);
-            }
+        String message = formatLogWithStack(messageTemplate, args);
+        Throwable tr = getThrowableToLog(args);
+        if (tr != null) {
+            android.util.Log.d(normalizeTag(tag), message, tr);
+        } else {
+            android.util.Log.d(normalizeTag(tag), message);
         }
     }
 
-    /** Sends a {@link android.util.Log#DEBUG} log message. 0 arg version. */
+    /** Sends a {@link android.util.Log#DEBUG} log message. 0 args version. */
+    @RemovableInRelease
+    @VisibleForTesting
     public static void d(String tag, String message) {
         debug(tag, message);
     }
 
     /** Sends a {@link android.util.Log#DEBUG} log message. 1 arg version. */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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 */
+    @RemovableInRelease
+    @VisibleForTesting
     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);
@@ -259,66 +262,63 @@
     /**
      * 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 tag Used to identify the source of a log message. Might be modified in the output
+     *            (see {@link #normalizeTag(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.
      */
+    @VisibleForTesting
     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);
-            }
+        String message = formatLog(messageTemplate, args);
+        Throwable tr = getThrowableToLog(args);
+        if (tr != null) {
+            android.util.Log.i(normalizeTag(tag), message, tr);
+        } else {
+            android.util.Log.i(normalizeTag(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 tag Used to identify the source of a log message. Might be modified in the output
+     *            (see {@link #normalizeTag(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.
      */
+    @VisibleForTesting
     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);
-            }
+        String message = formatLog(messageTemplate, args);
+        Throwable tr = getThrowableToLog(args);
+        if (tr != null) {
+            android.util.Log.w(normalizeTag(tag), message, tr);
+        } else {
+            android.util.Log.w(normalizeTag(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 tag Used to identify the source of a log message. Might be modified in the output
+     *            (see {@link #normalizeTag(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.
      */
+    @VisibleForTesting
     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);
-            }
+        String message = formatLog(messageTemplate, args);
+        Throwable tr = getThrowableToLog(args);
+        if (tr != null) {
+            android.util.Log.e(normalizeTag(tag), message, tr);
+        } else {
+            android.util.Log.e(normalizeTag(tag), message);
         }
     }
 
@@ -329,22 +329,21 @@
      *
      * @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 tag Used to identify the source of a log message. Might be modified in the output
+     *            (see {@link #normalizeTag(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.
      */
+    @VisibleForTesting
     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);
-            }
+        String message = formatLog(messageTemplate, args);
+        Throwable tr = getThrowableToLog(args);
+        if (tr != null) {
+            android.util.Log.wtf(normalizeTag(tag), message, tr);
+        } else {
+            android.util.Log.wtf(normalizeTag(tag), message);
         }
     }
 
diff --git a/base/android/java/src/org/chromium/base/MemoryPressureListener.java b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
index e7c2030..d61a006 100644
--- a/base/android/java/src/org/chromium/base/MemoryPressureListener.java
+++ b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
@@ -9,12 +9,16 @@
 import android.content.Context;
 import android.content.res.Configuration;
 
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.MainDex;
+
 
 /**
  * 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.
  */
+@MainDex
 public class MemoryPressureListener {
     /**
      * Sending an intent with this action to Chrome will cause it to issue a call to onLowMemory
@@ -72,10 +76,10 @@
         } 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 if (ACTION_TRIM_MEMORY_MODERATE.equals(action)) {
+            simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_MODERATE);
         } else {
             return false;
         }
diff --git a/base/android/java/src/org/chromium/base/PackageUtils.java b/base/android/java/src/org/chromium/base/PackageUtils.java
index ab554cd..b1cb29e 100644
--- a/base/android/java/src/org/chromium/base/PackageUtils.java
+++ b/base/android/java/src/org/chromium/base/PackageUtils.java
@@ -7,12 +7,30 @@
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 
 /**
  * This class provides package checking related methods.
  */
 public class PackageUtils {
     /**
+     * Retrieves the PackageInfo object for this application.
+     *
+     * @param context Any context.
+     * @return The PackageInfo object for this application.
+     */
+    public static PackageInfo getOwnPackageInfo(Context context) {
+        PackageManager manager = context.getPackageManager();
+        try {
+            String packageName = context.getApplicationContext().getPackageName();
+            return manager.getPackageInfo(packageName, 0);
+        } catch (NameNotFoundException e) {
+            // Should never happen.
+            throw new AssertionError("Failed to retrieve own package info");
+        }
+    }
+
+    /**
      * Retrieves the version of the given package installed on the device.
      *
      * @param context Any context.
diff --git a/base/android/java/src/org/chromium/base/PathService.java b/base/android/java/src/org/chromium/base/PathService.java
index b22328c..9807c2e 100644
--- a/base/android/java/src/org/chromium/base/PathService.java
+++ b/base/android/java/src/org/chromium/base/PathService.java
@@ -4,6 +4,8 @@
 
 package org.chromium.base;
 
+import org.chromium.base.annotations.JNINamespace;
+
 /**
  * This class provides java side access to the native PathService.
  */
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
index e46fc30..81c74f4 100644
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -8,13 +8,20 @@
 import android.content.pm.ApplicationInfo;
 import android.os.AsyncTask;
 import android.os.Environment;
+import android.os.StrictMode;
 
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.MainDex;
+
+import java.io.File;
 import java.util.concurrent.ExecutionException;
 
 /**
  * This class provides the path related methods for the native library.
  */
+@MainDex
 public abstract class PathUtils {
+    private static final String THUMBNAIL_DIRECTORY = "textures";
 
     private static final int DATA_DIRECTORY = 0;
     private static final int DATABASE_DIRECTORY = 1;
@@ -22,6 +29,8 @@
     private static final int NUM_DIRECTORIES = 3;
     private static AsyncTask<String, Void, String[]> sDirPathFetchTask;
 
+    private static File sThumbnailDirectory;
+
     // Prevent instantiation.
     private PathUtils() {}
 
@@ -91,14 +100,32 @@
         return getDirectoryPath(CACHE_DIRECTORY);
     }
 
+    public static File getThumbnailCacheDirectory(Context appContext) {
+        if (sThumbnailDirectory == null) {
+            sThumbnailDirectory = appContext.getDir(THUMBNAIL_DIRECTORY, Context.MODE_PRIVATE);
+        }
+        return sThumbnailDirectory;
+    }
+
+    @CalledByNative
+    public static String getThumbnailCacheDirectoryPath(Context appContext) {
+        return getThumbnailCacheDirectory(appContext).getAbsolutePath();
+    }
+
     /**
      * @return the public downloads directory.
      */
     @SuppressWarnings("unused")
     @CalledByNative
     private static String getDownloadsDirectory(Context appContext) {
-        return Environment.getExternalStoragePublicDirectory(
-                Environment.DIRECTORY_DOWNLOADS).getPath();
+        // Temporarily allowing disk access while fixing. TODO: http://crbug.com/508615
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            return Environment.getExternalStoragePublicDirectory(
+                    Environment.DIRECTORY_DOWNLOADS).getPath();
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
     }
 
     /**
diff --git a/base/android/java/src/org/chromium/base/PowerMonitor.java b/base/android/java/src/org/chromium/base/PowerMonitor.java
index 3d0ed48..485bc82 100644
--- a/base/android/java/src/org/chromium/base/PowerMonitor.java
+++ b/base/android/java/src/org/chromium/base/PowerMonitor.java
@@ -11,6 +11,9 @@
 import android.os.Handler;
 import android.os.Looper;
 
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
 
 /**
  * Integrates native PowerMonitor with the java side.
diff --git a/base/android/java/src/org/chromium/base/README_logging.md b/base/android/java/src/org/chromium/base/README_logging.md
deleted file mode 100644
index 2193826..0000000
--- a/base/android/java/src/org/chromium/base/README_logging.md
+++ /dev/null
@@ -1,159 +0,0 @@
-## 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
index d44f2fc..c8691bb 100644
--- a/base/android/java/src/org/chromium/base/ResourceExtractor.java
+++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java
@@ -6,17 +6,15 @@
 
 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 org.chromium.base.annotations.SuppressFBWarnings;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -28,7 +26,6 @@
 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
@@ -36,24 +33,26 @@
  */
 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 TAG = "cr.base";
     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;
+    private static ResourceEntry[] sResourcesToExtract = new ResourceEntry[0];
 
-    // 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;
+    /**
+     * Holds information about a res/raw file (e.g. locale .pak files).
+     */
+    public static final class ResourceEntry {
+        public final int resourceId;
+        public final String pathWithinApk;
+        public final String extractedFileName;
 
-    private static boolean isAppDataFile(String file) {
-        return ICU_DATA_FILENAME.equals(file)
-                || V8_NATIVES_DATA_FILENAME.equals(file)
-                || V8_SNAPSHOT_DATA_FILENAME.equals(file);
+        public ResourceEntry(int resourceId, String pathWithinApk, String extractedFileName) {
+            this.resourceId = resourceId;
+            this.pathWithinApk = pathWithinApk;
+            this.extractedFileName = extractedFileName;
+        }
     }
 
     private class ExtractTask extends AsyncTask<Void, Void, Void> {
@@ -61,14 +60,40 @@
 
         private final List<Runnable> mCompletionCallbacks = new ArrayList<Runnable>();
 
-        public ExtractTask() {
+        private void extractResourceHelper(InputStream is, File outFile, byte[] buffer)
+                throws IOException {
+            OutputStream os = null;
+            try {
+                os = new FileOutputStream(outFile);
+                Log.i(TAG, "Extracting resource %s", outFile);
+
+                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 (outFile.length() == 0) {
+                    throw new IOException(outFile + " extracted with 0 length!");
+                }
+            } finally {
+                try {
+                    if (is != null) {
+                        is.close();
+                    }
+                } finally {
+                    if (os != null) {
+                        os.close();
+                    }
+                }
+            }
         }
 
         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!");
+                Log.e(TAG, "Unable to create pak resources directory!");
                 return;
             }
 
@@ -83,97 +108,22 @@
                 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");
+            byte[] buffer = new byte[BUFFER_SIZE];
             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);
+                // Extract all files that don't already exist.
+                for (ResourceEntry entry : sResourcesToExtract) {
+                    File output = new File(outputDir, entry.extractedFileName);
                     if (output.exists()) {
                         continue;
                     }
-
-                    InputStream is = null;
-                    OutputStream os = null;
                     beginTraceSection("ExtractResource");
+                    InputStream inputStream = mContext.getResources().openRawResource(
+                            entry.resourceId);
                     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);
-                        }
+                        extractResourceHelper(inputStream, output, buffer);
                     } finally {
-                        try {
-                            if (is != null) {
-                                is.close();
-                            }
-                        } finally {
-                            if (os != null) {
-                                os.close();
-                            }
-                            endTraceSection(); // ExtractResource
-                        }
+                        endTraceSection(); // ExtractResource
                     }
                 }
             } catch (IOException e) {
@@ -181,7 +131,7 @@
                 // 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());
+                Log.w(TAG, "Exception unpacking required pak resources: %s", e.getMessage());
                 deleteFiles();
                 return;
             } finally {
@@ -195,7 +145,7 @@
                 } 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!");
+                    Log.w(TAG, "Failed to write resource pak timestamp!");
                 }
             }
         }
@@ -263,7 +213,7 @@
                 }
             });
 
-            if (timestamps.length != 1) {
+            if (timestamps == null || 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;
@@ -303,53 +253,19 @@
     }
 
     /**
-     * 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.
+     * Specifies the files that should be extracted from the APK.
+     * and moved to {@link #getOutputDir()}.
      */
-    public static void setMandatoryPaksToExtract(String... mandatoryPaks) {
+    @SuppressFBWarnings("EI_EXPOSE_STATIC_REP2")
+    public static void setResourcesToExtract(ResourceEntry[] entries) {
         assert (sInstance == null || sInstance.mExtractTask == null)
                 : "Must be called before startExtractingResources is called";
-        sMandatoryPaks = mandatoryPaks;
-
+        sResourcesToExtract = entries;
     }
 
-    /**
-     * 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()]));
+    // TODO(agrieve): Delete this method ones all usages of it are updated.
+    public static void setMandatoryPaksToExtract(String... paths) {
+        assert paths.length == 1 && "".equals(paths[0]);
     }
 
     private ResourceExtractor(Context context) {
@@ -421,6 +337,10 @@
             return;
         }
 
+        // If a previous release extracted resources, and the current release does not,
+        // deleteFiles() will not run and some files will be left. This currently
+        // can happen for ContentShell, but not for Chrome proper, since we always extract
+        // locale pak files.
         if (shouldSkipPakExtraction()) {
             return;
         }
@@ -449,36 +369,34 @@
     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());
+            Log.e(TAG, "Unable to remove the icudata %s", 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());
+            Log.e(TAG, "Unable to remove the v8 data %s", 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());
+            Log.e(TAG, "Unable to remove the v8 data %s", 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());
+
+            if (files != null) {
+                for (File file : files) {
+                    if (!file.delete()) {
+                        Log.e(TAG, "Unable to remove existing resource %s", 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.
+     * Pak extraction not necessarily required by the embedder.
      */
     private static boolean shouldSkipPakExtraction() {
-        // Must call setMandatoryPaksToExtract before beginning resource extraction.
-        assert sMandatoryPaks != null;
-        return sMandatoryPaks.length == 1 && "".equals(sMandatoryPaks[0]);
+        return sResourcesToExtract.length == 0;
     }
 }
diff --git a/base/android/java/src/org/chromium/base/StreamUtil.java b/base/android/java/src/org/chromium/base/StreamUtil.java
new file mode 100644
index 0000000..f8cbfee
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/StreamUtil.java
@@ -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.
+
+package org.chromium.base;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Helper methods to deal with stream related tasks.
+ */
+public class StreamUtil {
+    /**
+     * Handle closing a {@link java.io.Closeable} via {@link java.io.Closeable#close()} and catch
+     * the potentially thrown {@link java.io.IOException}.
+     * @param closeable The Closeable to be closed.
+     */
+    public static void closeQuietly(Closeable closeable) {
+        if (closeable == null) return;
+
+        try {
+            closeable.close();
+        } catch (IOException ex) {
+            // Ignore the exception on close.
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/SysUtils.java b/base/android/java/src/org/chromium/base/SysUtils.java
index 9dad516..74bac10 100644
--- a/base/android/java/src/org/chromium/base/SysUtils.java
+++ b/base/android/java/src/org/chromium/base/SysUtils.java
@@ -11,6 +11,8 @@
 import android.os.StrictMode;
 import android.util.Log;
 
+import org.chromium.base.annotations.CalledByNative;
+
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.util.regex.Matcher;
@@ -113,13 +115,10 @@
         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) {
+        // Only KitKat and later devices have isLowRamDevice() call available.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && context != null) {
             ActivityManager activityManager = (ActivityManager)
                     context.getSystemService(Context.ACTIVITY_SERVICE);
             if (activityManager.isLowRamDevice()) {
@@ -134,6 +133,6 @@
             return false;
         }
 
-        return ramSizeMB < ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB;
+        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
index fd3dc5a..ebcc0d9 100644
--- a/base/android/java/src/org/chromium/base/SystemMessageHandler.java
+++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
@@ -4,16 +4,21 @@
 
 package org.chromium.base;
 
+import android.annotation.SuppressLint;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
-import android.util.Log;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.MainDex;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
+@MainDex
 class SystemMessageHandler extends Handler {
 
-    private static final String TAG = "SystemMessageHandler";
+    private static final String TAG = "cr.SysMessageHandler";
 
     private static final int SCHEDULED_WORK = 1;
     private static final int DELAYED_SCHEDULED_WORK = 2;
@@ -22,27 +27,8 @@
     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
@@ -77,28 +63,93 @@
     }
 
     private Message obtainAsyncMessage(int what) {
+        // Marking the message async provides fair Chromium task dispatch when
+        // served by the Android UI thread's Looper, avoiding stalls when the
+        // Looper has a sync barrier.
         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;
+        MessageCompat.setAsynchronous(msg, true);
+        return msg;
+    }
+
+    /**
+     * Abstraction utility class for marking a Message as asynchronous. Prior
+     * to L MR1 the async Message API was hidden, and for such cases we fall
+     * back to using reflection to obtain the necessary method.
+     */
+    private static class MessageCompat {
+        /**
+         * @See android.os.Message#setAsynchronous(boolean)
+         */
+        public static void setAsynchronous(Message message, boolean async) {
+            IMPL.setAsynchronous(message, async);
+        }
+
+        interface MessageWrapperImpl {
+            /**
+             * @See android.os.Message#setAsynchronous(boolean)
+             */
+            public void setAsynchronous(Message message, boolean async);
+        }
+
+        static final MessageWrapperImpl IMPL;
+        static {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
+                IMPL = new LollipopMr1MessageWrapperImpl();
+            } else {
+                IMPL = new LegacyMessageWrapperImpl();
             }
         }
-        return msg;
+
+        static class LollipopMr1MessageWrapperImpl implements MessageWrapperImpl {
+            @SuppressLint("NewApi")
+            @Override
+            public void setAsynchronous(Message msg, boolean async) {
+                msg.setAsynchronous(async);
+            }
+        }
+
+        static class LegacyMessageWrapperImpl implements MessageWrapperImpl {
+            // Reflected API for marking a message as asynchronous.
+            // Note: Use of this API is experimental and likely to evolve in the future.
+            private Method mMessageMethodSetAsynchronous;
+
+            LegacyMessageWrapperImpl() {
+                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 setAsynchronous(Message msg, boolean async) {
+                if (mMessageMethodSetAsynchronous == null) return;
+                // If invocation fails, assume this is indicative of future
+                // failures, and avoid log spam by nulling the reflected method.
+                try {
+                    mMessageMethodSetAsynchronous.invoke(msg, async);
+                } catch (IllegalAccessException e) {
+                    Log.e(TAG, "Illegal access to async message creation, disabling.");
+                    mMessageMethodSetAsynchronous = null;
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "Illegal argument for async message creation, disabling.");
+                    mMessageMethodSetAsynchronous = null;
+                } catch (InvocationTargetException e) {
+                    Log.e(TAG, "Invocation exception during async message creation, disabling.");
+                    mMessageMethodSetAsynchronous = null;
+                } catch (RuntimeException e) {
+                    Log.e(TAG, "Runtime exception during async message creation, disabling.");
+                    mMessageMethodSetAsynchronous = null;
+                }
+            }
+        }
     }
 
     @CalledByNative
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
index c0b9172..ef2887a 100644
--- a/base/android/java/src/org/chromium/base/ThreadUtils.java
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -8,6 +8,8 @@
 import android.os.Looper;
 import android.os.Process;
 
+import org.chromium.base.annotations.CalledByNative;
+
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.FutureTask;
@@ -29,6 +31,7 @@
         }
     }
 
+    @VisibleForTesting
     public static void setUiThread(Looper looper) {
         synchronized (sLock) {
             if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
@@ -80,6 +83,7 @@
      * @param c The Callable to run
      * @return The result of the callable
      */
+    @VisibleForTesting
     public static <T> T runOnUiThreadBlockingNoException(Callable<T> c) {
         try {
             return runOnUiThreadBlocking(c);
@@ -206,4 +210,14 @@
     public static void setThreadPriorityAudio(int tid) {
         Process.setThreadPriority(tid, Process.THREAD_PRIORITY_AUDIO);
     }
+
+    /**
+     * Checks whether Thread priority is THREAD_PRIORITY_AUDIO or not.
+     * @param tid Thread id.
+     * @return true for THREAD_PRIORITY_AUDIO and false otherwise.
+     */
+    @CalledByNative
+    private static boolean isThreadPriorityAudio(int tid) {
+        return Process.getThreadPriority(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
index 3d3b11a..878275c 100644
--- a/base/android/java/src/org/chromium/base/TraceEvent.java
+++ b/base/android/java/src/org/chromium/base/TraceEvent.java
@@ -9,6 +9,9 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.Printer;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
 /**
  * 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()
@@ -20,6 +23,7 @@
 public class TraceEvent {
 
     private static volatile boolean sEnabled = false;
+    private static volatile boolean sATraceEnabled = false; // True when taking an Android systrace.
 
     private static class BasicLooperMonitor implements Printer {
         @Override
@@ -176,6 +180,8 @@
     @CalledByNative
     public static void setEnabled(boolean enabled) {
         sEnabled = enabled;
+        // Android M+ systrace logs this on its own. Only log it if not writing to Android systrace.
+        if (sATraceEnabled) return;
         ThreadUtils.getUiThreadLooper().setMessageLogging(
                 enabled ? LooperMonitorHolder.sInstance : null);
     }
@@ -186,10 +192,15 @@
      * systrace, this is for WebView only.
      */
     public static void setATraceEnabled(boolean enabled) {
-        if (sEnabled == enabled) return;
+        if (sATraceEnabled == enabled) return;
+        sATraceEnabled = enabled;
         if (enabled) {
+            // Calls TraceEvent.setEnabled(true) via
+            // TraceLog::EnabledStateObserver::OnTraceLogEnabled
             nativeStartATrace();
         } else {
+            // Calls TraceEvent.setEnabled(false) via
+            // TraceLog::EnabledStateObserver::OnTraceLogDisabled
             nativeStopATrace();
         }
     }
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..89be90b
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/WindowCallbackWrapper.java
@@ -0,0 +1,149 @@
+// Copyright 2015 The Chromium 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.annotation.TargetApi;
+import android.os.Build;
+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.SearchEvent;
+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);
+    }
+
+    @Override
+    @TargetApi(Build.VERSION_CODES.M)
+    public boolean onSearchRequested(SearchEvent searchEvent) {
+        return mCallback.onSearchRequested(searchEvent);
+    }
+
+    @Override
+    @TargetApi(Build.VERSION_CODES.M)
+    public ActionMode onWindowStartingActionMode(Callback callback, int type) {
+        return mCallback.onWindowStartingActionMode(callback, type);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/CalledByNative.java b/base/android/java/src/org/chromium/base/annotations/CalledByNative.java
similarity index 94%
rename from base/android/java/src/org/chromium/base/CalledByNative.java
rename to base/android/java/src/org/chromium/base/annotations/CalledByNative.java
index 3e6315e..94ef3fa 100644
--- a/base/android/java/src/org/chromium/base/CalledByNative.java
+++ b/base/android/java/src/org/chromium/base/annotations/CalledByNative.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.base;
+package org.chromium.base.annotations;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
diff --git a/base/android/java/src/org/chromium/base/JNIAdditionalImport.java b/base/android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java
similarity index 96%
rename from base/android/java/src/org/chromium/base/JNIAdditionalImport.java
rename to base/android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java
index 499d158..f1bf85e 100644
--- a/base/android/java/src/org/chromium/base/JNIAdditionalImport.java
+++ b/base/android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.base;
+package org.chromium.base.annotations;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
diff --git a/base/android/java/src/org/chromium/base/JNINamespace.java b/base/android/java/src/org/chromium/base/annotations/JNINamespace.java
similarity index 93%
rename from base/android/java/src/org/chromium/base/JNINamespace.java
rename to base/android/java/src/org/chromium/base/annotations/JNINamespace.java
index 5ad7a42..4cd5531 100644
--- a/base/android/java/src/org/chromium/base/JNINamespace.java
+++ b/base/android/java/src/org/chromium/base/annotations/JNINamespace.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.base;
+package org.chromium.base.annotations;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
diff --git a/base/android/java/src/org/chromium/base/annotations/MainDex.java b/base/android/java/src/org/chromium/base/annotations/MainDex.java
new file mode 100644
index 0000000..0b35ade
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/MainDex.java
@@ -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.
+
+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;
+
+/**
+ * An annotation that signals that a class should be kept in the main dex file.
+ *
+ * This generally means it's used by renderer processes, which can't load secondary dexes
+ * on K and below.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface MainDex {
+}
diff --git a/base/android/java/src/org/chromium/base/NativeCall.java b/base/android/java/src/org/chromium/base/annotations/NativeCall.java
similarity index 95%
rename from base/android/java/src/org/chromium/base/NativeCall.java
rename to base/android/java/src/org/chromium/base/annotations/NativeCall.java
index 352edf7..b69cd17 100644
--- a/base/android/java/src/org/chromium/base/NativeCall.java
+++ b/base/android/java/src/org/chromium/base/annotations/NativeCall.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.base;
+package org.chromium.base.annotations;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
diff --git a/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java b/base/android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java
similarity index 95%
rename from base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
rename to base/android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java
index e55b18c..afbc368 100644
--- a/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
+++ b/base/android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.base;
+package org.chromium.base.annotations;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
diff --git a/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java b/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
deleted file mode 100644
index 803c3f9..0000000
--- a/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 The Chromium 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/RemovableInRelease.java b/base/android/java/src/org/chromium/base/annotations/RemovableInRelease.java
new file mode 100644
index 0000000..2191334
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/RemovableInRelease.java
@@ -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.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * The annotated function can be removed in release builds.
+ *
+ * Calls to this function will be removed if its return value is not used. If all calls are removed,
+ * the function definition itself will be candidate for removal.
+ * It works by indicating to Proguard that the function has no side effects.
+ */
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface RemovableInRelease {}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java b/base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java
new file mode 100644
index 0000000..d0ab312
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LegacyLinker.java
@@ -0,0 +1,639 @@
+// Copyright 2015 The Chromium 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 org.chromium.base.Log;
+import org.chromium.base.SysUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.MainDex;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/*
+ * For more, see Technical note, Security considerations, and the explanation
+ * of how this class is supposed to be used in Linker.java.
+ */
+
+/**
+ * Provides a concrete implementation of the Chromium Linker.
+ *
+ * This Linker implementation uses the crazy linker to map and then run Chrome
+ * for Android.
+ *
+ * For more on the operations performed by the Linker, see {@link Linker}.
+ */
+@MainDex
+class LegacyLinker extends Linker {
+    // Log tag for this class.
+    private static final String TAG = "LibraryLoader";
+
+    // Becomes true after linker initialization.
+    private boolean mInitialized = false;
+
+    // Set to true if this runs in the browser process. Disabled by initServiceProcess().
+    private boolean mInBrowserProcess = true;
+
+    // Becomes true to indicate this process needs to wait for a shared RELRO in
+    // finishLibraryLoad().
+    private boolean mWaitForSharedRelros = false;
+
+    // Becomes true when initialization determines that the browser process can use the
+    // shared RELRO.
+    private boolean mBrowserUsesSharedRelro = false;
+
+    // The map of all RELRO sections either created or used in this process.
+    private Bundle mSharedRelros = null;
+
+    // Current common random base load address. A value of -1 indicates not yet initialized.
+    private long mBaseLoadAddress = -1;
+
+    // Current fixed-location load address for the next library called by loadLibrary().
+    // A value of -1 indicates not yet initialized.
+    private long mCurrentLoadAddress = -1;
+
+    // Becomes true once prepareLibraryLoad() has been called.
+    private boolean mPrepareLibraryLoadCalled = false;
+
+    // The map of libraries that are currently loaded in this process.
+    private HashMap<String, LibInfo> mLoadedLibraries = null;
+
+    // Private singleton constructor, and singleton factory method.
+    private LegacyLinker() { }
+    static Linker create() {
+        return new LegacyLinker();
+    }
+
+    // Used internally to initialize the linker's data. Assumes lock is held.
+    // Loads JNI, and sets mMemoryDeviceConfig and mBrowserUsesSharedRelro.
+    private void ensureInitializedLocked() {
+        assert Thread.holdsLock(mLock);
+
+        if (mInitialized || !NativeLibraries.sUseLinker) {
+            return;
+        }
+
+        // On first call, load libchromium_android_linker.so. Cannot be done in the
+        // constructor because instantiation occurs on the UI thread.
+        loadLinkerJniLibrary();
+
+        if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
+            if (SysUtils.isLowEndDevice()) {
+                mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_LOW;
+            } else {
+                mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_NORMAL;
+            }
+        }
+
+        // Cannot run in the constructor because SysUtils.isLowEndDevice() relies
+        // on CommandLine, which may not be available at instantiation.
+        switch (BROWSER_SHARED_RELRO_CONFIG) {
+            case BROWSER_SHARED_RELRO_CONFIG_NEVER:
+                mBrowserUsesSharedRelro = false;
+                break;
+            case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
+                if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
+                    mBrowserUsesSharedRelro = true;
+                    Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
+                } else {
+                    mBrowserUsesSharedRelro = false;
+                }
+                break;
+            case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
+                Log.w(TAG, "Beware: shared RELROs used in all processes!");
+                mBrowserUsesSharedRelro = true;
+                break;
+            default:
+                assert false : "Unreached";
+                break;
+        }
+
+        mInitialized = true;
+    }
+
+    /**
+     * Call this method to determine if the linker will try to use shared RELROs
+     * for the browser process.
+     */
+    @Override
+    public boolean isUsingBrowserSharedRelros() {
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            return mInBrowserProcess && mBrowserUsesSharedRelro;
+        }
+    }
+
+    /**
+     * Call this method just before loading any native shared libraries in this process.
+     */
+    @Override
+    public void prepareLibraryLoad() {
+        if (DEBUG) {
+            Log.i(TAG, "prepareLibraryLoad() called");
+        }
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            mPrepareLibraryLoadCalled = true;
+
+            if (mInBrowserProcess) {
+                // 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().
+     */
+    @Override
+    public void finishLibraryLoad() {
+        if (DEBUG) {
+            Log.i(TAG, "finishLibraryLoad() called");
+        }
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            if (DEBUG) {
+                Log.i(TAG, String.format(
+                        Locale.US,
+                        "mInBrowserProcess=%b mBrowserUsesSharedRelro=%b mWaitForSharedRelros=%b",
+                        mInBrowserProcess, mBrowserUsesSharedRelro, mWaitForSharedRelros));
+            }
+
+            if (mLoadedLibraries == null) {
+                if (DEBUG) {
+                    Log.i(TAG, "No libraries loaded");
+                }
+            } else {
+                if (mInBrowserProcess) {
+                    // Create new Bundle containing RELRO section information
+                    // for all loaded libraries. Make it available to getSharedRelros().
+                    mSharedRelros = createBundleFromLibInfoMap(mLoadedLibraries);
+                    if (DEBUG) {
+                        Log.i(TAG, "Shared RELRO created");
+                        dumpBundle(mSharedRelros);
+                    }
+
+                    if (mBrowserUsesSharedRelro) {
+                        useSharedRelrosLocked(mSharedRelros);
+                    }
+                }
+
+                if (mWaitForSharedRelros) {
+                    assert !mInBrowserProcess;
+
+                    // Wait until the shared relro bundle is received from useSharedRelros().
+                    while (mSharedRelros == null) {
+                        try {
+                            mLock.wait();
+                        } catch (InterruptedException ie) {
+                            // Restore the thread's interrupt status.
+                            Thread.currentThread().interrupt();
+                        }
+                    }
+                    useSharedRelrosLocked(mSharedRelros);
+                    // Clear the Bundle to ensure its file descriptor references can't be reused.
+                    mSharedRelros.clear();
+                    mSharedRelros = null;
+                }
+            }
+
+            // If testing, run tests now that all libraries are loaded and initialized.
+            if (NativeLibraries.sEnableLinkerTests) {
+                runTestRunnerClassForTesting(mMemoryDeviceConfig, mInBrowserProcess);
+            }
+        }
+        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.
+     */
+    @Override
+    public 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 (mLock) {
+            // Note that in certain cases, this can be called before
+            // initServiceProcess() in service processes.
+            mSharedRelros = clonedBundle;
+            // Tell any listener blocked in finishLibraryLoad() about it.
+            mLock.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.
+     */
+    @Override
+    public Bundle getSharedRelros() {
+        if (DEBUG) {
+            Log.i(TAG, "getSharedRelros() called");
+        }
+        synchronized (mLock) {
+            if (!mInBrowserProcess) {
+                if (DEBUG) {
+                    Log.i(TAG, "... returning null Bundle");
+                }
+                return null;
+            }
+
+            // Return the Bundle created in finishLibraryLoad().
+            if (DEBUG) {
+                Log.i(TAG, "... returning " + mSharedRelros);
+            }
+            return mSharedRelros;
+        }
+    }
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process shall neither create or reuse shared RELRO sections.
+     */
+    @Override
+    public void disableSharedRelros() {
+        if (DEBUG) {
+            Log.i(TAG, "disableSharedRelros() called");
+        }
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            mInBrowserProcess = false;
+            mWaitForSharedRelros = false;
+            mBrowserUsesSharedRelro = 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.
+     */
+    @Override
+    public void initServiceProcess(long baseLoadAddress) {
+        if (DEBUG) {
+            Log.i(TAG, String.format(
+                    Locale.US, "initServiceProcess(0x%x) called",
+                    baseLoadAddress));
+        }
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            mInBrowserProcess = false;
+            mBrowserUsesSharedRelro = false;
+            mWaitForSharedRelros = true;
+            mBaseLoadAddress = baseLoadAddress;
+            mCurrentLoadAddress = 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.
+     */
+    @Override
+    public long getBaseLoadAddress() {
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            if (!mInBrowserProcess) {
+                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",
+                        mBaseLoadAddress));
+            }
+            return mBaseLoadAddress;
+        }
+    }
+
+    // Used internally to lazily setup the common random base load address.
+    private void setupBaseLoadAddressLocked() {
+        assert Thread.holdsLock(mLock);
+        if (mBaseLoadAddress == -1) {
+            mBaseLoadAddress = getRandomBaseLoadAddress();
+            mCurrentLoadAddress = mBaseLoadAddress;
+            if (mBaseLoadAddress == 0) {
+                // If the random 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");
+                mBrowserUsesSharedRelro = false;
+                mWaitForSharedRelros = false;
+            }
+        }
+    }
+
+    // Used for debugging only.
+    private 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 void useSharedRelrosLocked(Bundle bundle) {
+        assert Thread.holdsLock(mLock);
+
+        if (DEBUG) {
+            Log.i(TAG, "Linker.useSharedRelrosLocked() called");
+        }
+
+        if (bundle == null) {
+            if (DEBUG) {
+                Log.i(TAG, "null bundle!");
+            }
+            return;
+        }
+
+        if (mLoadedLibraries == 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 (!mInBrowserProcess) {
+            closeLibInfoMap(relroMap);
+        }
+
+        if (DEBUG) {
+            Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
+        }
+    }
+
+    /**
+     * Implements loading a native shared library with the Chromium linker.
+     *
+     * 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).
+     * @param isFixedAddressPermitted If true, uses a fixed load address if one was
+     * supplied, otherwise ignores the fixed address and loads wherever available.
+     */
+    @Override
+    void loadLibraryImpl(@Nullable String zipFilePath,
+                         String libFilePath,
+                         boolean isFixedAddressPermitted) {
+        if (DEBUG) {
+            Log.i(TAG, "loadLibraryImpl: "
+                    + zipFilePath + ", " + libFilePath + ", " + isFixedAddressPermitted);
+        }
+        synchronized (mLock) {
+            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 mPrepareLibraryLoadCalled;
+
+            if (mLoadedLibraries == null) {
+                mLoadedLibraries = new HashMap<String, LibInfo>();
+            }
+
+            if (mLoadedLibraries.containsKey(libFilePath)) {
+                if (DEBUG) {
+                    Log.i(TAG, "Not loading " + libFilePath + " twice");
+                }
+                return;
+            }
+
+            LibInfo libInfo = new LibInfo();
+            long loadAddress = 0;
+            if (isFixedAddressPermitted) {
+                if ((mInBrowserProcess && mBrowserUsesSharedRelro) || mWaitForSharedRelros) {
+                    // Load the library at a fixed address.
+                    loadAddress = mCurrentLoadAddress;
+
+                    // For multiple libraries, ensure we stay within reservation range.
+                    if (loadAddress > mBaseLoadAddress + ADDRESS_SPACE_RESERVATION) {
+                        String errorMessage =
+                                "Load address outside reservation, for: " + libFilePath;
+                        Log.e(TAG, errorMessage);
+                        throw new UnsatisfiedLinkError(errorMessage);
+                    }
+                }
+            }
+
+            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) {
+                String tag = mInBrowserProcess ? "BROWSER_LIBRARY_ADDRESS"
+                                               : "RENDERER_LIBRARY_ADDRESS";
+                Log.i(TAG, String.format(
+                        Locale.US, "%s: %s %x", tag, libFilePath, libInfo.mLoadAddress));
+            }
+
+            if (mInBrowserProcess) {
+                // Create a new shared RELRO section at the 'current' fixed load address.
+                if (!nativeCreateSharedRelro(sharedRelRoName, mCurrentLoadAddress, libInfo)) {
+                    Log.w(TAG, String.format(
+                            Locale.US, "Could not create shared RELRO for %s at %x",
+                            libFilePath,
+                            mCurrentLoadAddress));
+                } else {
+                    if (DEBUG) {
+                        Log.i(TAG, String.format(
+                                Locale.US,
+                                "Created shared RELRO for %s at %x: %s",
+                                sharedRelRoName,
+                                mCurrentLoadAddress,
+                                libInfo.toString()));
+                    }
+                }
+            }
+
+            if (loadAddress != 0 && mCurrentLoadAddress != 0) {
+                // Compute the next current load address. If mCurrentLoadAddress
+                // is not 0, this is an explicit library load address. Otherwise,
+                // this is an explicit load address for relocated RELRO sections
+                // only.
+                mCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize
+                                      + BREAKPAD_GUARD_REGION_BYTES;
+            }
+
+            mLoadedLibraries.put(sharedRelRoName, libInfo);
+            if (DEBUG) {
+                Log.i(TAG, "Library details " + libInfo.toString());
+            }
+        }
+    }
+
+    /**
+     * 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(@Nullable String zipfileName,
+                                                             String libraryName,
+                                                             long loadAddress,
+                                                             LibInfo libInfo);
+
+    /**
+     * Native method used to create a shared RELRO section.
+     * If the library was already loaded at the same address using
+     * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
+     * this loads a new temporary library at the specified address,
+     * creates and extracts the RELRO section from it, then unloads it.
+     *
+     * @param library Library name.
+     * @param loadAddress load address, which can be different from the one
+     * used to load the library in the current process!
+     * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
+     * and mRelroFd will be set.
+     * @return true on success, false otherwise.
+     */
+    private static native boolean nativeCreateSharedRelro(String library,
+                                                          long loadAddress,
+                                                          LibInfo libInfo);
+
+    /**
+     * Native method used to use a shared RELRO section.
+     *
+     * @param library Library name.
+     * @param libInfo A LibInfo instance containing valid RELRO information
+     * @return true on success.
+     */
+    private static native boolean nativeUseSharedRelro(String library,
+                                                       LibInfo libInfo);
+}
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
index 9dc6865..8b61bca 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -4,19 +4,23 @@
 
 package org.chromium.base.library_loader;
 
+import android.annotation.TargetApi;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.SystemClock;
-import android.util.Log;
 
-import org.chromium.base.CalledByNative;
 import org.chromium.base.CommandLine;
-import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
+import org.chromium.base.PackageUtils;
 import org.chromium.base.TraceEvent;
-import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.metrics.RecordHistogram;
 
-import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.annotation.Nullable;
 
@@ -66,30 +70,23 @@
     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;
 
+    // One-way switch that becomes true once
+    // {@link asyncPrefetchLibrariesToMemory} has been called.
+    private final AtomicBoolean mPrefetchLibraryHasBeenCalled;
+
+    // The number of milliseconds it took to load all the native libraries, which
+    // will be reported via UMA. Set once when the libraries are done loading.
+    private long mLibraryLoadTimeMs;
+
     /**
      * @param libraryProcessType the process the shared library is loaded in. refer to
      *                           LibraryProcessType for possible values.
@@ -109,38 +106,21 @@
 
     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);
+        mPrefetchLibraryHasBeenCalled = new AtomicBoolean();
     }
 
     /**
      *  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.
+     *  @param context The context in which the method is called.
      */
-    public void ensureInitialized(
-            Context context, boolean shouldDeleteFallbackLibraries)
-            throws ProcessInitException {
+    public void ensureInitialized(Context context) throws ProcessInitException {
         synchronized (sLock) {
             if (mInitialized) {
                 // Already initialized, nothing to do.
                 return;
             }
-            loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
+            loadAlreadyLocked(context);
             initializeAlreadyLocked();
         }
     }
@@ -153,32 +133,19 @@
     }
 
     /**
-     * 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.
+     * @param context The context the code is running.
      *
      * @throws ProcessInitException if the native library failed to load.
      */
-    public void loadNow(Context context, boolean shouldDeleteFallbackLibraries)
-            throws ProcessInitException {
+    public void loadNow(Context context) throws ProcessInitException {
         synchronized (sLock) {
-            loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
+            loadAlreadyLocked(context);
         }
     }
 
@@ -201,10 +168,9 @@
      *
      * 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) {
+    public void asyncPrefetchLibrariesToMemory() {
+        if (!mPrefetchLibraryHasBeenCalled.compareAndSet(false, true)) return;
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
@@ -220,59 +186,50 @@
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
-    // Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code
-    private void loadAlreadyLocked(
-            Context context, boolean shouldDeleteFallbackLibraries)
-            throws ProcessInitException {
+    // Helper for loadAlreadyLocked(). Load a native shared library with the Chromium linker.
+    // Sets UMA flags depending on the results of loading.
+    private void loadLibrary(Linker linker, @Nullable String zipFilePath, String libFilePath) {
+        if (linker.isUsingBrowserSharedRelros()) {
+            // If the browser is set to attempt shared RELROs then we try first with shared
+            // RELROs enabled, and if that fails then retry without.
+            mIsUsingBrowserSharedRelros = true;
+            try {
+                linker.loadLibrary(zipFilePath, libFilePath);
+            } catch (UnsatisfiedLinkError e) {
+                Log.w(TAG, "Failed to load native library with shared RELRO, retrying without");
+                mLoadAtFixedAddressFailed = true;
+                linker.loadLibraryNoFixedAddress(zipFilePath, libFilePath);
+            }
+        } else {
+            // No attempt to use shared RELROs in the browser, so load as normal.
+            linker.loadLibrary(zipFilePath, libFilePath);
+        }
+
+        // Loaded successfully, so record if we loaded directly from an APK.
+        if (zipFilePath != null) {
+            mLibraryWasLoadedFromApk = true;
+        }
+    }
+
+    // Invoke either Linker.loadLibrary(...) or System.loadLibrary(...), triggering
+    // JNI_OnLoad in native code
+    private void loadAlreadyLocked(Context context) 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");
-                    }
-
+                if (Linker.isUsed()) {
                     // Load libraries using the Chromium linker.
-                    Linker.prepareLibraryLoad();
+                    Linker linker = Linker.getInstance();
+                    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 (linker.isChromiumLinkerLibrary(library)) {
                             if (DEBUG) Log.i(TAG, "ignoring self-linker load");
                             continue;
                         }
@@ -280,55 +237,20 @@
                         // 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);
-                            }
+                        if (Linker.isInZipFile()) {
+                            // Load directly from the APK.
+                            zipFilePath = getLibraryApkPath(context);
+                            Log.i(TAG, "Loading " + library + " from within " + zipFilePath);
                         } 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);
-                        }
+                        // Load the library using this Linker. May throw UnsatisfiedLinkError.
+                        loadLibrary(linker, zipFilePath, libFilePath);
                     }
 
-                    Linker.finishLibraryLoad();
+                    linker.finishLibraryLoad();
                 } else {
                     // Load libraries using the system linker.
                     for (String library : NativeLibraries.LIBRARIES) {
@@ -336,15 +258,10 @@
                     }
                 }
 
-                if (!fallbackWasUsed && context != null
-                        && shouldDeleteFallbackLibraries) {
-                    LibraryLoaderHelper.deleteLibrariesAsynchronously(
-                            context, LibraryLoaderHelper.LOAD_FROM_APK_FALLBACK_DIR);
-                }
-
                 long stopTime = SystemClock.uptimeMillis();
+                mLibraryLoadTimeMs = stopTime - startTime;
                 Log.i(TAG, String.format("Time to load native libraries: %d ms (timestamps %d-%d)",
-                        stopTime - startTime,
+                        mLibraryLoadTimeMs,
                         startTime % 10000,
                         stopTime % 10000));
 
@@ -355,7 +272,7 @@
         }
         // 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\","
+                "Expected native library version number \"%s\", "
                         + "actual native library version number \"%s\"",
                 NativeLibraries.sVersionNumber,
                 nativeGetVersionNumber()));
@@ -364,13 +281,29 @@
         }
     }
 
-    // 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;
+    // Returns whether the given split name is that of the ABI split.
+    private static boolean isAbiSplit(String splitName) {
+        // The split name for the ABI split is manually set in the build rules.
+        return splitName.startsWith("abi_");
+    }
+
+    // Returns the path to the .apk that holds the native libraries.
+    // This is either the main .apk, or the abi split apk.
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    private static String getLibraryApkPath(Context context) {
+        ApplicationInfo appInfo = context.getApplicationInfo();
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+            return appInfo.sourceDir;
         }
+        PackageInfo packageInfo = PackageUtils.getOwnPackageInfo(context);
+        if (packageInfo.splitNames != null) {
+            for (int i = 0; i < packageInfo.splitNames.length; ++i) {
+                if (isAbiSplit(packageInfo.splitNames[i])) {
+                    return appInfo.splitSourceDirs[i];
+                }
+            }
+        }
+        return appInfo.sourceDir;
     }
 
     // The WebView requires the Command Line to be switched over before
@@ -437,40 +370,25 @@
     // Record Chromium linker histogram state for the main browser process. Called from
     // onNativeInitializationComplete().
     private void recordBrowserProcessHistogram(Context context) {
-        if (Linker.isUsed()) {
+        if (Linker.getInstance().isUsed()) {
             nativeRecordChromiumAndroidLinkerBrowserHistogram(mIsUsingBrowserSharedRelros,
                                                               mLoadAtFixedAddressFailed,
-                                                              getLibraryLoadFromApkStatus(context));
+                                                              getLibraryLoadFromApkStatus(context),
+                                                              mLibraryLoadTimeMs);
         }
     }
 
     // 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();
+        assert Linker.getInstance().isUsed();
 
         if (mLibraryWasLoadedFromApk) {
-            return mMapApkWithExecPermission
-                    ? LibraryLoadFromApkStatusCodes.SUCCESSFUL
-                    : LibraryLoadFromApkStatusCodes.USED_NO_MAP_EXEC_SUPPORT_FALLBACK;
+            return LibraryLoadFromApkStatusCodes.SUCCESSFUL;
         }
 
-        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;
+        // There were no libraries to be loaded directly from the APK file.
+        return LibraryLoadFromApkStatusCodes.UNKNOWN;
     }
 
     // Register pending Chromium linker histogram state for renderer processes. This cannot be
@@ -479,9 +397,10 @@
     // RecordChromiumAndroidLinkerRendererHistogram() will record it correctly.
     public void registerRendererProcessHistogram(boolean requestedSharedRelro,
                                                  boolean loadAtFixedAddressFailed) {
-        if (Linker.isUsed()) {
+        if (Linker.getInstance().isUsed()) {
             nativeRegisterChromiumAndroidLinkerRendererHistogram(requestedSharedRelro,
-                                                                 loadAtFixedAddressFailed);
+                                                                 loadAtFixedAddressFailed,
+                                                                 mLibraryLoadTimeMs);
         }
     }
 
@@ -508,18 +427,22 @@
     // 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.
+    // support for loading a library directly from the APK file, and the number of milliseconds
+    // it took to load the libraries.
     private native void nativeRecordChromiumAndroidLinkerBrowserHistogram(
             boolean isUsingBrowserSharedRelros,
             boolean loadAtFixedAddressFailed,
-            int libraryLoadFromApkStatus);
+            int libraryLoadFromApkStatus,
+            long libraryLoadTime);
 
     // 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.
+    // and if it did, whether the library failed to load at a fixed address. Also records the
+    // number of milliseconds it took to load the libraries.
     private native void nativeRegisterChromiumAndroidLinkerRendererHistogram(
             boolean requestedSharedRelro,
-            boolean loadAtFixedAddressFailed);
+            boolean loadAtFixedAddressFailed,
+            long libraryLoadTime);
 
     // 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.
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
deleted file mode 100644
index 7dd1a29..0000000
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright 2014 The Chromium 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
index 7e50998..8b8d906 100644
--- a/base/android/java/src/org/chromium/base/library_loader/Linker.java
+++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -1,21 +1,18 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium 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.Build;
 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.Log;
 import org.chromium.base.annotations.AccessedByNative;
 
-import java.io.FileNotFoundException;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
@@ -60,7 +57,7 @@
  *
  * - 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.
+ *   depends on the configuration variable BROWSER_SHARED_RELRO_CONFIG.
  *
  *   Not using fixed library addresses in the browser process is preferred
  *   for regular devices since it maintains the efficacy of ASLR as an
@@ -71,20 +68,14 @@
  *   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
+ * - Once the RELRO ashmem region or file is mapped into a service process's
+ *   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.
+ *   the program on the device. See getRandomBaseLoadAddress() for more
+ *   details on how this is obtained.
  *
  * - When loading several libraries in service processes, a simple incremental
  *   approach from the original random base load address is used. This is
@@ -97,8 +88,8 @@
  * 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).
+ *    instead of System.loadLibrary(). The two functions should behave the same
+ *    (at a high level).
  *
  *  - Before loading any library, prepareLibraryLoad() should be called.
  *
@@ -147,22 +138,21 @@
  *    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.
+ *  - In a service process, finishLibraryLoad() and/or loadLibrary() may
+ *    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 {
+public abstract class Linker {
+    // Log tag for this class.
+    private static final String TAG = "LibraryLoader";
 
-    // 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;
+    // Name of the library that contains our JNI code.
+    private static final String LINKER_JNI_LIBRARY = "chromium_android_linker";
 
     // Constants used to control the behaviour of the browser process with
-    // regards to the shared RELRO section.
+    // regards to the shared RELRO section. Not applicable to ModernLinker.
     //   NEVER        -> The browser never uses it itself.
     //   LOW_RAM_ONLY -> It is only used on devices with low RAM.
     //   ALWAYS       -> It is always used.
@@ -173,11 +163,13 @@
 
     // Configuration variable used to control how the browser process uses the
     // shared RELRO. Only change this while debugging linker-related issues.
+    // Not used by ModernLinker.
     // 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.
+    // Constants used to control the memory device config. Can be set explicitly
+    // by setMemoryDeviceConfigForTesting(). Not applicable to ModernLinker.
     //   INIT         -> Value is undetermined (will check at runtime).
     //   LOW          -> This is a low-memory device.
     //   NORMAL       -> This is not a low-memory device.
@@ -187,97 +179,159 @@
 
     // 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;
+    // for testing by calling setMemoryDeviceConfigForTesting().
+    // Not used by ModernLinker.
+    protected int mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
 
-    // Becomes true after linker initialization.
-    private static boolean sInitialized = false;
+    // Set to true to enable debug logs.
+    protected static final boolean DEBUG = false;
 
-    // Set to true to indicate that the system supports safe sharing of RELRO sections.
-    private static boolean sRelroSharingSupported = false;
+    // Used to pass the shared RELRO Bundle through Binder.
+    public static final String EXTRA_LINKER_SHARED_RELROS =
+            "org.chromium.base.android.linker.shared_relros";
 
-    // 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;
+    // Guards all access to the linker.
+    protected final Object mLock = new Object();
 
-    // Becomes true to indicate this process needs to wait for a shared RELRO in
-    // finishLibraryLoad().
-    private static boolean sWaitForSharedRelros = false;
+    // The name of a class that implements TestRunner.
+    private String mTestRunnerClassName = null;
 
-    // Becomes true when initialization determines that the browser process can use the
-    // shared RELRO.
-    private static boolean sBrowserUsesSharedRelro = false;
+    // Size of reserved Breakpad guard region. Should match the value of
+    // kBreakpadGuardRegionBytes on the JNI side. Used when computing the load
+    // addresses of multiple loaded libraries. Set to 0 to disable the guard.
+    protected static final int BREAKPAD_GUARD_REGION_BYTES = 16 * 1024 * 1024;
 
-    // The map of all RELRO sections either created or used in this process.
-    private static Bundle sSharedRelros = null;
+    // Size of the area requested when using ASLR to obtain a random load address.
+    // Should match the value of kAddressSpaceReservationSize on the JNI side.
+    // Used when computing the load addresses of multiple loaded libraries to
+    // ensure that we don't try to load outside the area originally requested.
+    protected static final int ADDRESS_SPACE_RESERVATION = 192 * 1024 * 1024;
 
-    // Current common random base load address.
-    private static long sBaseLoadAddress = 0;
+    // Constants used to indicate a given Linker implementation, for testing.
+    //   LEGACY       -> Always uses the LegacyLinker implementation.
+    //   MODERN       -> Always uses the ModernLinker implementation.
+    // NOTE: These names are known and expected by the Linker test scripts.
+    public static final int LINKER_IMPLEMENTATION_LEGACY = 1;
+    public static final int LINKER_IMPLEMENTATION_MODERN = 2;
 
-    // Current fixed-location load address for the next library called by loadLibrary().
-    private static long sCurrentLoadAddress = 0;
+    // Singleton.
+    private static Linker sSingleton = null;
+    private static Object sSingletonLock = new Object();
 
-    // Becomes true once prepareLibraryLoad() has been called.
-    private static boolean sPrepareLibraryLoadCalled = false;
+    // Protected singleton constructor.
+    protected Linker() { }
 
-    // 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");
+    /**
+     * Get singleton instance. Returns either a LegacyLinker or a ModernLinker.
+     *
+     * Returns a ModernLinker if running on Android M or later, otherwise returns
+     * a LegacyLinker.
+     *
+     * ModernLinker requires OS features from Android M and later: a system linker
+     * that handles packed relocations and load from APK, and android_dlopen_ext()
+     * for shared RELRO support. It cannot run on Android releases earlier than M.
+     *
+     * LegacyLinker runs on all Android releases but it is slower and more complex
+     * than ModernLinker, so ModernLinker is preferred for Android M and later.
+     *
+     * @return the Linker implementation instance.
+     */
+    public static final Linker getInstance() {
+        synchronized (sSingletonLock) {
+            if (sSingleton == null) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                    sSingleton = ModernLinker.create();
                 } else {
-                    if (DEBUG) Log.i(TAG, "This system supports safe shared RELRO sections");
+                    sSingleton = LegacyLinker.create();
                 }
+                Log.i(TAG, "Using linker: " + sSingleton.getClass().getName());
+            }
+            return sSingleton;
+        }
+    }
 
-                if (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
-                    sMemoryDeviceConfig = SysUtils.isLowEndDevice()
-                            ? MEMORY_DEVICE_CONFIG_LOW : MEMORY_DEVICE_CONFIG_NORMAL;
-                }
+    /**
+     * Check that native library linker tests are enabled.
+     * If not enabled, calls to testing functions will fail with an assertion
+     * error.
+     *
+     * @return true if native library linker tests are enabled.
+     */
+    public static boolean areTestsEnabled() {
+        return NativeLibraries.sEnableLinkerTests;
+    }
 
-                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;
-                }
+    /**
+     * Assert for testing.
+     * Hard assertion. Cannot be disabled. Used only by testing methods.
+     */
+    private static void assertForTesting(boolean flag) {
+        if (!flag) {
+            throw new AssertionError();
+        }
+    }
+
+    /**
+     * Assert NativeLibraries.sEnableLinkerTests is true.
+     * Hard assertion that we are in a testing context. Cannot be disabled. The
+     * test methods in this module permit injection of runnable code by class
+     * name. To protect against both malicious and accidental use of these
+     * methods, we ensure that NativeLibraries.sEnableLinkerTests is true when
+     * any is called.
+     */
+    private static void assertLinkerTestsAreEnabled() {
+        if (!NativeLibraries.sEnableLinkerTests) {
+            throw new AssertionError("Testing method called in non-testing context");
+        }
+    }
+
+    /**
+     * Set Linker implementation type.
+     * For testing. Sets either a LegacyLinker or a ModernLinker. Must be called
+     * before getInstance().
+     *
+     * @param type LINKER_IMPLEMENTATION_LEGACY or LINKER_IMPLEMENTATION_MODERN
+     */
+    public static final void setImplementationForTesting(int type) {
+        // Sanity check. This method may only be called during tests.
+        assertLinkerTestsAreEnabled();
+        assertForTesting(type == LINKER_IMPLEMENTATION_LEGACY
+                         || type == LINKER_IMPLEMENTATION_MODERN);
+
+        synchronized (sSingletonLock) {
+            assertForTesting(sSingleton == null);
+
+            if (type == LINKER_IMPLEMENTATION_MODERN) {
+                sSingleton = ModernLinker.create();
+            } else if (type == LINKER_IMPLEMENTATION_LEGACY) {
+                sSingleton = LegacyLinker.create();
+            }
+            Log.i(TAG, "Forced linker: " + sSingleton.getClass().getName());
+        }
+    }
+
+    /**
+     * Get Linker implementation type.
+     * For testing.
+     *
+     * @return LINKER_IMPLEMENTATION_LEGACY or LINKER_IMPLEMENTATION_MODERN
+     */
+    public final int getImplementationForTesting() {
+        // Sanity check. This method may only be called during tests.
+        assertLinkerTestsAreEnabled();
+
+        synchronized (sSingletonLock) {
+            assertForTesting(sSingleton == this);
+
+            if (sSingleton instanceof ModernLinker) {
+                return LINKER_IMPLEMENTATION_MODERN;
+            } else if (sSingleton instanceof LegacyLinker) {
+                return LINKER_IMPLEMENTATION_LEGACY;
             } else {
-                if (DEBUG) Log.i(TAG, "Linker disabled");
+                Log.wtf(TAG, "Invalid linker: " + sSingleton.getClass().getName());
+                assertForTesting(false);
             }
-
-            if (!sRelroSharingSupported) {
-                // Sanity.
-                sBrowserUsesSharedRelro = false;
-                sWaitForSharedRelros = false;
-            }
-
-            sInitialized = true;
+            return 0;
         }
     }
 
@@ -290,32 +344,31 @@
     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.
+         * @return true if all checks pass.
          */
         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;
+    public final void setTestRunnerClassNameForTesting(String testRunnerClassName) {
+        if (DEBUG) {
+            Log.i(TAG, "setTestRunnerClassNameForTesting(" + testRunnerClassName + ") called");
         }
+        // Sanity check. This method may only be called during tests.
+        assertLinkerTestsAreEnabled();
 
-        synchronized (Linker.class) {
-            assert sTestRunnerClassName == null;
-            sTestRunnerClassName = testRunnerClassName;
+        synchronized (mLock) {
+            assertForTesting(mTestRunnerClassName == null);
+            mTestRunnerClassName = testRunnerClassName;
         }
     }
 
@@ -323,382 +376,182 @@
      * 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.
+     * the TestRunner set by calling setTestRunnerClassNameForTesting() previously.
      */
-    public static String getTestRunnerClassName() {
-        synchronized (Linker.class) {
-            return sTestRunnerClassName;
+    public final String getTestRunnerClassNameForTesting() {
+        // Sanity check. This method may only be called during tests.
+        assertLinkerTestsAreEnabled();
+
+        synchronized (mLock) {
+            return mTestRunnerClassName;
+        }
+    }
+
+    /**
+     * Set up the Linker for a test.
+     * Convenience function that calls setImplementationForTesting() to force an
+     * implementation, and then setTestRunnerClassNameForTesting() to set the test
+     * class name.
+     *
+     * On first call, instantiates a Linker of the requested type and sets its test
+     * runner class name. On subsequent calls, checks that the singleton produced by
+     * the first call matches the requested type and test runner class name.
+     */
+    public static final void setupForTesting(int type, String testRunnerClassName) {
+        if (DEBUG) {
+            Log.i(TAG, "setupForTesting(" + type + ", " + testRunnerClassName + ") called");
+        }
+        // Sanity check. This method may only be called during tests.
+        assertLinkerTestsAreEnabled();
+
+        synchronized (sSingletonLock) {
+            // If this is the first call, configure the Linker to the given type and test class.
+            if (sSingleton == null) {
+                setImplementationForTesting(type);
+                sSingleton.setTestRunnerClassNameForTesting(testRunnerClassName);
+                return;
+            }
+
+            // If not the first call, check that the Linker configuration matches this request.
+            assertForTesting(sSingleton.getImplementationForTesting() == type);
+            String ourTestRunnerClassName = sSingleton.getTestRunnerClassNameForTesting();
+            if (testRunnerClassName == null) {
+                assertForTesting(ourTestRunnerClassName == null);
+            } else {
+                assertForTesting(ourTestRunnerClassName.equals(testRunnerClassName));
+            }
+        }
+    }
+
+    /**
+     * Instantiate and run the current TestRunner, if any. The TestRunner implementation
+     * must be instantiated _after_ all libraries are loaded to ensure that its
+     * native methods are properly registered.
+     *
+     * @param memoryDeviceConfig LegacyLinker memory config, or 0 if unused
+     * @param inBrowserProcess true if in the browser process
+     */
+    protected final void runTestRunnerClassForTesting(int memoryDeviceConfig,
+                                                      boolean inBrowserProcess) {
+        if (DEBUG) {
+            Log.i(TAG, "runTestRunnerClassForTesting called");
+        }
+        // Sanity check. This method may only be called during tests.
+        assertLinkerTestsAreEnabled();
+
+        synchronized (mLock) {
+            if (mTestRunnerClassName == null) {
+                Log.wtf(TAG, "Linker runtime tests not set up for this process");
+                assertForTesting(false);
+            }
+            if (DEBUG) {
+                Log.i(TAG, "Instantiating " + mTestRunnerClassName);
+            }
+            TestRunner testRunner = null;
+            try {
+                testRunner = (TestRunner) Class.forName(mTestRunnerClassName).newInstance();
+            } catch (Exception e) {
+                Log.wtf(TAG, "Could not instantiate test runner class by name", e);
+                assertForTesting(false);
+            }
+
+            if (!testRunner.runChecks(memoryDeviceConfig, inBrowserProcess)) {
+                Log.wtf(TAG, "Linker runtime tests failed in this process");
+                assertForTesting(false);
+            }
+
+            Log.i(TAG, "All linker tests passed");
         }
     }
 
     /**
      * 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.
+     *
+     * @param memoryDeviceConfig 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;
+    public final void setMemoryDeviceConfigForTesting(int memoryDeviceConfig) {
+        if (DEBUG) {
+            Log.i(TAG, "setMemoryDeviceConfigForTesting(" + memoryDeviceConfig + ") called");
+        }
+        // Sanity check. This method may only be called during tests.
+        assertLinkerTestsAreEnabled();
+        assertForTesting(memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
+                         || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL);
+
+        synchronized (mLock) {
+            assertForTesting(mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT);
+
+            mMemoryDeviceConfig = memoryDeviceConfig;
             if (DEBUG) {
-                if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
+                if (mMemoryDeviceConfig == 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.
+     * Determine whether a library is the linker library. Also deal with the
+     * component build that adds a .cr suffix to the name.
+     *
+     * @param library the name of the library.
+     * @return true is the library is the Linker's own JNI library.
      */
-    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;
-        }
+    public boolean isChromiumLinkerLibrary(String library) {
+        return library.equals(LINKER_JNI_LIBRARY) || library.equals(LINKER_JNI_LIBRARY + ".cr");
     }
 
     /**
-     * Call this method to determine if the linker will try to use shared RELROs
-     * for the browser process.
+     * Load the Linker JNI library. Throws UnsatisfiedLinkError on error.
+     * In a component build, the suffix ".cr" is added to each library name, so
+     * if the initial load fails we retry with a suffix.
      */
-    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();
-        }
+    protected static void loadLinkerJniLibrary() {
+        String libName = "lib" + LINKER_JNI_LIBRARY + ".so";
         if (DEBUG) {
-            Log.i(TAG, "useSharedRelros() called with " + bundle
-                    + ", cloned " + clonedBundle);
+            Log.i(TAG, "Loading " + libName);
         }
-        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();
+        try {
+            System.loadLibrary(LINKER_JNI_LIBRARY);
+        } catch (UnsatisfiedLinkError e) {
+            Log.w(TAG, "Couldn't load " + libName + ", trying " + libName + ".cr");
+            System.loadLibrary(LINKER_JNI_LIBRARY + ".cr");
         }
     }
 
     /**
-     * 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.
+     * Obtain a random base load address at which to place loaded libraries.
+     *
+     * @return new base load address
      */
-    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() {
+    protected long getRandomBaseLoadAddress() {
         // 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.
+        // successfully mapped an area larger than the largest library we expect to load,
+        // 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.
+        // we will load is. If it is smaller than the size we used to obtain a random
+        // address 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);
+        final long address = nativeGetRandomBaseLoadAddress();
         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
@@ -709,308 +562,133 @@
      * @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());
+    public void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
+        if (DEBUG) {
+            Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath);
         }
+        final boolean isFixedAddressPermitted = true;
+        loadLibraryImpl(zipFilePath, libFilePath, isFixedAddressPermitted);
     }
 
     /**
-     * Enable the fallback due to lack of support for mapping the APK file with
-     * executable permission (see crbug.com/398425).
+     * Load a native shared library with the Chromium linker, ignoring any
+     * requested fixed address for RELRO sharing. 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 enableNoMapExecSupportFallback() {
-        synchronized (Linker.class) {
-            ensureInitializedLocked();
-
-            if (DEBUG) Log.i(TAG, "Enabling no map executable support fallback");
-            nativeEnableNoMapExecSupportFallback();
+    public void loadLibraryNoFixedAddress(@Nullable String zipFilePath, String libFilePath) {
+        if (DEBUG) {
+            Log.i(TAG, "loadLibraryAtAnyAddress: " + zipFilePath + ", " + libFilePath);
         }
+        final boolean isFixedAddressPermitted = false;
+        loadLibraryImpl(zipFilePath, libFilePath, isFixedAddressPermitted);
     }
 
     /**
-     * Determine whether a library is the linker library. Also deal with the
-     * component build that adds a .cr suffix to the name.
+     * Call this method to determine if the chromium project must load the library
+     * directly from a zip file.
      */
-    public static boolean isChromiumLinkerLibrary(String library) {
-        return library.equals(TAG) || library.equals(TAG + ".cr");
+    public static boolean isInZipFile() {
+        // The auto-generated NativeLibraries.sUseLibraryInZipFile variable will be true
+        // if the library remains embedded in the APK zip file on the target.
+        return NativeLibraries.sUseLibraryInZipFile;
     }
 
     /**
-     * Get the full library path in zip file (lib/<abi>/crazy.<lib_name>).
-     *
-     * @param library The library's base name.
-     * @return the library path.
+     * 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 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;
-        }
+    public static boolean isUsed() {
+        // The auto-generated NativeLibraries.sUseLinker variable will be true if the
+        // build has not explicitly disabled Linker features.
+        return NativeLibraries.sUseLinker;
     }
 
     /**
-     * Check whether the device supports mapping the APK file with executable permission.
+     * Call this method to determine if the linker will try to use shared RELROs
+     * for the browser process.
+     */
+    public abstract boolean isUsingBrowserSharedRelros();
+
+    /**
+     * Call this method just before loading any native shared libraries in this process.
+     */
+    public abstract void prepareLibraryLoad();
+
+    /**
+     * Call this method just after loading all native shared libraries in this process.
+     */
+    public abstract void finishLibraryLoad();
+
+    /**
+     * 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 apkFile Filename of the APK.
-     * @return true if supported.
+     * @param bundle The Bundle instance containing a map of shared RELRO sections
+     * to use in this process.
      */
-    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;
-        }
-    }
+    public abstract void useSharedRelros(Bundle bundle);
 
     /**
-     * Check whether a library is page aligned and uncompressed in the APK file.
+     * Call this to retrieve the shared RELRO sections created in this process,
+     * after loading all libraries.
      *
-     * @param apkFile Filename of the APK.
-     * @param library The library's base name.
-     * @return true if page aligned and uncompressed.
+     * @return a new Bundle instance, or null if RELRO sharing is disabled on
+     * this system, or if initServiceProcess() was called previously.
      */
-    public static boolean checkLibraryIsMappableInApk(String apkFile, String library) {
-        synchronized (Linker.class) {
-            ensureInitializedLocked();
+    public abstract Bundle getSharedRelros();
 
-            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.
+     * Call this method before loading any libraries to indicate that this
+     * process shall neither create or reuse shared RELRO sections.
+     */
+    public abstract void disableSharedRelros();
+
+    /**
+     * 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 opaque Opaque argument.
+     * @param baseLoadAddress the base library load address to use.
      */
-    @CalledByNative
-    public static void postCallbackOnMainThread(final long opaque) {
-        ThreadUtils.postOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                nativeRunCallbackOnUiThread(opaque);
-            }
-        });
-    }
+    public abstract void initServiceProcess(long baseLoadAddress);
 
     /**
-     * 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.
+     * 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().
      *
-     * @param apkFile Filename of the APK.
-     * @return true if supported.
+     * @return a common, random base load address, or 0 if RELRO sharing is
+     * disabled.
      */
-    private static native boolean nativeCheckMapExecSupport(String apkFile);
+    public abstract long getBaseLoadAddress();
 
     /**
-     * Native method which checks whether a library is page aligned and
-     * uncompressed in the APK file.
+     * Implements loading a native shared library with the Chromium linker.
      *
-     * @param apkFile Filename of the APK.
-     * @param library The library's base name.
-     * @return true if page aligned and uncompressed.
+     * @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).
+     * @param isFixedAddressPermitted If true, uses a fixed load address if one was
+     * supplied, otherwise ignores the fixed address and loads wherever available.
      */
-    private static native boolean nativeCheckLibraryIsMappableInApk(String apkFile, String library);
+    abstract void loadLibraryImpl(@Nullable String zipFilePath,
+                                  String libFilePath,
+                                  boolean isFixedAddressPermitted);
 
     /**
      * 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.
+     * Also, the LibInfo instance owns the shared RELRO file descriptor.
      */
     public static class LibInfo implements Parcelable {
 
@@ -1027,7 +705,9 @@
                 try {
                     ParcelFileDescriptor.adoptFd(mRelroFd).close();
                 } catch (java.io.IOException e) {
-                    if (DEBUG) Log.e(TAG, "Failed to close fd: " + mRelroFd);
+                    if (DEBUG) {
+                        Log.e(TAG, "Failed to close fd: " + mRelroFd);
+                    }
                 }
                 mRelroFd = -1;
             }
@@ -1057,7 +737,7 @@
                     fd.writeToParcel(out, 0);
                     fd.close();
                 } catch (java.io.IOException e) {
-                    Log.e(TAG, "Cant' write LibInfo file descriptor to parcel", e);
+                    Log.e(TAG, "Can't write LibInfo file descriptor to parcel", e);
                 }
             }
         }
@@ -1104,21 +784,20 @@
         @AccessedByNative
         public long mRelroSize;   // page-aligned size in memory, or 0.
         @AccessedByNative
-        public int  mRelroFd;     // ashmem file descriptor, or -1
+        public int  mRelroFd;     // shared RELRO file descriptor, or -1
     }
 
     // Create a Bundle from a map of LibInfo objects.
-    private static Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
+    protected 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) {
+    protected HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
         HashMap<String, LibInfo> map = new HashMap<String, LibInfo>();
         for (String library : bundle.keySet()) {
             LibInfo libInfo = bundle.getParcelable(library);
@@ -1128,16 +807,20 @@
     }
 
     // Call the close() method on all values of a LibInfo map.
-    private static void closeLibInfoMap(HashMap<String, LibInfo> map) {
+    protected 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";
+    /**
+     * Return a random address that should be free to be mapped with the given size.
+     * Maps an area large enough for the largest library we might attempt to load,
+     * 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.
+     *
+     * @return address to pass to future mmap, or 0 on error.
+     */
+    private static native long nativeGetRandomBaseLoadAddress();
 }
diff --git a/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java b/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java
new file mode 100644
index 0000000..5abc4e5
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java
@@ -0,0 +1,498 @@
+// Copyright 2015 The Chromium 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.SystemClock;
+
+import org.chromium.base.Log;
+import org.chromium.base.PathUtils;
+
+import java.util.HashMap;
+import java.util.Locale;
+
+import javax.annotation.Nullable;
+
+/*
+ * For more, see Technical note, Security considerations, and the explanation
+ * of how this class is supposed to be used in Linker.java.
+ */
+
+/**
+ * Provides a concrete implementation of the Chromium Linker.
+ *
+ * This Linker implementation uses the Android M and later system linker to map and then
+ * run Chrome for Android.
+ *
+ * For more on the operations performed by the Linker, see {@link Linker}.
+ */
+class ModernLinker extends Linker {
+    // Log tag for this class.
+    private static final String TAG = "LibraryLoader";
+
+    // Becomes true after linker initialization.
+    private boolean mInitialized = false;
+
+    // Becomes true to indicate this process needs to wait for a shared RELRO in LibraryLoad().
+    private boolean mWaitForSharedRelros = false;
+
+    // The map of all RELRO sections either created or used in this process.
+    private HashMap<String, LibInfo> mSharedRelros = null;
+
+    // Cached Bundle representation of the RELRO sections map for transfer across processes.
+    private Bundle mSharedRelrosBundle = null;
+
+    // Set to true if this runs in the browser process. Disabled by initServiceProcess().
+    private boolean mInBrowserProcess = true;
+
+    // Current common random base load address. A value of -1 indicates not yet initialized.
+    private long mBaseLoadAddress = -1;
+
+    // Current fixed-location load address for the next library called by loadLibrary().
+    // Initialized to mBaseLoadAddress in prepareLibraryLoad(), and then adjusted as each
+    // library is loaded by loadLibrary().
+    private long mCurrentLoadAddress = -1;
+
+    // Becomes true once prepareLibraryLoad() has been called.
+    private boolean mPrepareLibraryLoadCalled = false;
+
+    // The map of libraries that are currently loaded in this process.
+    private HashMap<String, LibInfo> mLoadedLibraries = null;
+
+    // The directory used to hold shared RELRO data files. Set up by prepareLibraryLoad().
+    private String mDataDirectory = null;
+
+    // Private singleton constructor, and singleton factory method.
+    private ModernLinker() { }
+    static Linker create() {
+        return new ModernLinker();
+    }
+
+    // Used internally to initialize the linker's data. Assumes lock is held.
+    private void ensureInitializedLocked() {
+        assert Thread.holdsLock(mLock);
+        assert NativeLibraries.sUseLinker;
+
+        // On first call, load libchromium_android_linker.so. Cannot be done in the
+        // constructor because the instance is constructed on the UI thread.
+        if (!mInitialized) {
+            loadLinkerJniLibrary();
+            mInitialized = true;
+        }
+    }
+
+    /**
+     * Call this method to determine if the linker will try to use shared RELROs
+     * for the browser process.
+     */
+    @Override
+    public boolean isUsingBrowserSharedRelros() {
+        // This Linker does not attempt to share RELROS between the browser and
+        // the renderers, but only between renderers.
+        return false;
+    }
+
+    /**
+     * Call this method just before loading any native shared libraries in this process.
+     * Loads the Linker's JNI library, and initializes the variables involved in the
+     * implementation of shared RELROs.
+     */
+    @Override
+    public void prepareLibraryLoad() {
+        if (DEBUG) {
+            Log.i(TAG, "prepareLibraryLoad() called");
+        }
+        assert NativeLibraries.sUseLinker;
+
+        synchronized (mLock) {
+            assert !mPrepareLibraryLoadCalled;
+            ensureInitializedLocked();
+
+            // If in the browser, generate a random base load address for service processes
+            // and create an empty shared RELROs map. For service processes, the shared
+            // RELROs map must remain null until set by useSharedRelros().
+            if (mInBrowserProcess) {
+                setupBaseLoadAddressLocked();
+                mSharedRelros = new HashMap<String, LibInfo>();
+            }
+
+            // Create an empty loaded libraries map.
+            mLoadedLibraries = new HashMap<String, LibInfo>();
+
+            // Retrieve the data directory from base.
+            mDataDirectory = PathUtils.getDataDirectory(null);
+
+            // Start the current load address at the base load address.
+            mCurrentLoadAddress = mBaseLoadAddress;
+
+            mPrepareLibraryLoadCalled = true;
+        }
+    }
+
+    /**
+     * Call this method just after loading all native shared libraries in this process.
+     * If not in the browser, closes the LibInfo entries used for RELRO sharing.
+     */
+    @Override
+    public void finishLibraryLoad() {
+        if (DEBUG) {
+            Log.i(TAG, "finishLibraryLoad() called");
+        }
+
+        synchronized (mLock) {
+            assert mPrepareLibraryLoadCalled;
+
+            // Close shared RELRO file descriptors if not in the browser.
+            if (!mInBrowserProcess && mSharedRelros != null) {
+                closeLibInfoMap(mSharedRelros);
+                mSharedRelros = null;
+            }
+
+            // If testing, run tests now that all libraries are loaded and initialized.
+            if (NativeLibraries.sEnableLinkerTests) {
+                runTestRunnerClassForTesting(0, mInBrowserProcess);
+            }
+        }
+    }
+
+    // Used internally to wait for shared RELROs. Returns once useSharedRelros() has been
+    // called to supply a valid shared RELROs bundle.
+    private void waitForSharedRelrosLocked() {
+        if (DEBUG) {
+            Log.i(TAG, "waitForSharedRelros called");
+        }
+        assert Thread.holdsLock(mLock);
+
+        // Return immediately if shared RELROs are already available.
+        if (mSharedRelros != null) {
+            return;
+        }
+
+        // Wait until notified by useSharedRelros() that shared RELROs have arrived.
+        long startTime = DEBUG ? SystemClock.uptimeMillis() : 0;
+        // Note: The additional synchronized block is present only to silence Findbugs.
+        // Without it, Findbugs reports a false positive:
+        // RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE: Redundant nullcheck of value known to be null
+        synchronized (mLock) {
+            while (mSharedRelros == null) {
+                try {
+                    mLock.wait();
+                } catch (InterruptedException e) {
+                    // Restore the thread's interrupt status.
+                    Thread.currentThread().interrupt();
+                }
+            }
+        }
+
+        if (DEBUG) {
+            Log.i(TAG, String.format(
+                    Locale.US, "Time to wait for shared RELRO: %d ms",
+                    SystemClock.uptimeMillis() - startTime));
+        }
+    }
+
+    /**
+     * Call this to send a Bundle containing the shared RELRO sections to be
+     * used in this process. If initServiceProcess() was previously called,
+     * libraryLoad() will wait 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.
+     */
+    @Override
+    public void useSharedRelros(Bundle bundle) {
+        if (DEBUG) {
+            Log.i(TAG, "useSharedRelros() called with " + bundle);
+        }
+
+        synchronized (mLock) {
+            mSharedRelros = createLibInfoMapFromBundle(bundle);
+            mLock.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.
+     */
+    @Override
+    public Bundle getSharedRelros() {
+        if (DEBUG) {
+            Log.i(TAG, "getSharedRelros() called");
+        }
+        synchronized (mLock) {
+            if (!mInBrowserProcess) {
+                if (DEBUG) {
+                    Log.i(TAG, "Not in browser, so returning null Bundle");
+                }
+                return null;
+            }
+
+            // Create a new Bundle containing RELRO section information for all the shared
+            // RELROs created while loading libraries.
+            if (mSharedRelrosBundle == null && mSharedRelros != null) {
+                mSharedRelrosBundle = createBundleFromLibInfoMap(mSharedRelros);
+                if (DEBUG) {
+                    Log.i(TAG, "Shared RELRO bundle created from map: " + mSharedRelrosBundle);
+                }
+            }
+            if (DEBUG) {
+                Log.i(TAG, "Returning " + mSharedRelrosBundle);
+            }
+            return mSharedRelrosBundle;
+        }
+    }
+
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process shall neither create or reuse shared RELRO sections.
+     */
+    @Override
+    public void disableSharedRelros() {
+        if (DEBUG) {
+            Log.i(TAG, "disableSharedRelros() called");
+        }
+        synchronized (mLock) {
+            assert !mPrepareLibraryLoadCalled;
+
+            // Mark this as a service process, and disable wait for shared RELRO.
+            mInBrowserProcess = false;
+            mWaitForSharedRelros = 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.
+     */
+    @Override
+    public void initServiceProcess(long baseLoadAddress) {
+        if (DEBUG) {
+            Log.i(TAG, String.format(
+                    Locale.US, "initServiceProcess(0x%x) called",
+                    baseLoadAddress));
+        }
+        synchronized (mLock) {
+            assert !mPrepareLibraryLoadCalled;
+
+            // Mark this as a service process, and flag wait for shared RELRO.
+            // Save the base load address passed in.
+            mInBrowserProcess = false;
+            mWaitForSharedRelros = true;
+            mBaseLoadAddress = baseLoadAddress;
+        }
+    }
+
+    /**
+     * Retrieve the base load address for libraries that share RELROs.
+     *
+     * @return a common, random base load address, or 0 if RELRO sharing is
+     * disabled.
+     */
+    @Override
+    public long getBaseLoadAddress() {
+        synchronized (mLock) {
+            ensureInitializedLocked();
+            setupBaseLoadAddressLocked();
+            if (DEBUG) {
+                Log.i(TAG, String.format(
+                        Locale.US, "getBaseLoadAddress() returns 0x%x",
+                        mBaseLoadAddress));
+            }
+            return mBaseLoadAddress;
+        }
+    }
+
+    // Used internally to lazily setup the common random base load address.
+    private void setupBaseLoadAddressLocked() {
+        assert Thread.holdsLock(mLock);
+
+        // No-op if the base load address is already set up.
+        if (mBaseLoadAddress == -1) {
+            mBaseLoadAddress = getRandomBaseLoadAddress();
+        }
+        if (mBaseLoadAddress == 0) {
+            // If the random 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");
+            mWaitForSharedRelros = false;
+        }
+    }
+
+    /**
+     * 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. The library must not be the Chromium linker library.
+     *
+     * If asked to wait for shared RELROs, this function will block library loads
+     * until the shared RELROs bundle is received by useSharedRelros().
+     *
+     * @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).
+     * @param isFixedAddressPermitted If true, uses a fixed load address if one was
+     * supplied, otherwise ignores the fixed address and loads wherever available.
+     */
+    @Override
+    void loadLibraryImpl(@Nullable String zipFilePath,
+                         String libFilePath,
+                         boolean isFixedAddressPermitted) {
+        if (DEBUG) {
+            Log.i(TAG, "loadLibraryImpl: "
+                    + zipFilePath + ", " + libFilePath + ", " + isFixedAddressPermitted);
+        }
+
+        synchronized (mLock) {
+            assert mPrepareLibraryLoadCalled;
+
+            String dlopenExtPath;
+            if (zipFilePath != null) {
+                // The android_dlopen_ext() function understands strings with the format
+                // <zip_path>!/<file_path> to represent the file_path element within the zip
+                // file at zip_path. This enables directly loading from APK. We add the
+                // "crazy." prefix to the path in the zip file to prevent the Android package
+                // manager from seeing this as a library and so extracting it from the APK.
+                String cpuAbi = nativeGetCpuAbi();
+                dlopenExtPath = zipFilePath + "!/lib/" + cpuAbi + "/crazy." + libFilePath;
+            } else {
+                // Not loading from APK directly, so simply pass the library name to
+                // android_dlopen_ext().
+                dlopenExtPath = libFilePath;
+            }
+
+            if (mLoadedLibraries.containsKey(dlopenExtPath)) {
+                if (DEBUG) {
+                    Log.i(TAG, "Not loading " + libFilePath + " twice");
+                }
+                return;
+            }
+
+            // If not in the browser, shared RELROs are not disabled, and fixed addresses
+            // have not been disallowed, load the library at a fixed address. Otherwise,
+            // load anywhere.
+            long loadAddress = 0;
+            if (!mInBrowserProcess && mWaitForSharedRelros && isFixedAddressPermitted) {
+                loadAddress = mCurrentLoadAddress;
+
+                // For multiple libraries, ensure we stay within reservation range.
+                if (loadAddress > mBaseLoadAddress + ADDRESS_SPACE_RESERVATION) {
+                    String errorMessage = "Load address outside reservation, for: " + libFilePath;
+                    Log.e(TAG, errorMessage);
+                    throw new UnsatisfiedLinkError(errorMessage);
+                }
+            }
+
+            LibInfo libInfo = new LibInfo();
+
+            if (mInBrowserProcess && mCurrentLoadAddress != 0) {
+                // We are in the browser, and with a current load address that indicates that
+                // there is enough address space for shared RELRO to operate. Create the
+                // shared RELRO, and store it in the map.
+                String relroPath = mDataDirectory + "/RELRO:" + libFilePath;
+                if (nativeCreateSharedRelro(dlopenExtPath,
+                                            mCurrentLoadAddress, relroPath, libInfo)) {
+                    mSharedRelros.put(dlopenExtPath, libInfo);
+                } else {
+                    String errorMessage = "Unable to create shared relro: " + relroPath;
+                    Log.w(TAG, errorMessage);
+                }
+            } else if (!mInBrowserProcess && mCurrentLoadAddress != 0 && mWaitForSharedRelros) {
+                // We are in a service process, again with a current load address that is
+                // suitable for shared RELRO, and we are to wait for shared RELROs. So
+                // do that, then use the map we receive to provide libinfo for library load.
+                waitForSharedRelrosLocked();
+                if (mSharedRelros.containsKey(dlopenExtPath)) {
+                    libInfo = mSharedRelros.get(dlopenExtPath);
+                }
+            }
+
+            // Load the library. In the browser, loadAddress is 0, so nativeLoadLibrary()
+            // will load without shared RELRO. Otherwise, it uses shared RELRO if the attached
+            // libInfo is usable.
+            if (!nativeLoadLibrary(dlopenExtPath, loadAddress, libInfo)) {
+                String errorMessage = "Unable to load library: " + dlopenExtPath;
+                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) {
+                String tag = mInBrowserProcess ? "BROWSER_LIBRARY_ADDRESS"
+                                               : "RENDERER_LIBRARY_ADDRESS";
+                Log.i(TAG, String.format(
+                        Locale.US, "%s: %s %x", tag, libFilePath, libInfo.mLoadAddress));
+            }
+
+            if (loadAddress != 0 && mCurrentLoadAddress != 0) {
+                // Compute the next current load address. If mCurrentLoadAddress
+                // is not 0, this is an explicit library load address.
+                mCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize
+                                      + BREAKPAD_GUARD_REGION_BYTES;
+            }
+
+            mLoadedLibraries.put(dlopenExtPath, libInfo);
+            if (DEBUG) {
+                Log.i(TAG, "Library details " + libInfo.toString());
+            }
+        }
+    }
+
+    /**
+     * Native method to return the CPU ABI.
+     * Obtaining it from the linker's native code means that we always correctly
+     * match the loaded library's ABI to the linker's ABI.
+     *
+     * @return CPU ABI string.
+     */
+    private static native String nativeGetCpuAbi();
+
+    /**
+     * Native method used to load a library.
+     *
+     * @param dlopenExtPath For load from APK, the path to the enclosing
+     * zipfile concatenated with "!/" and the path to the library within the zipfile;
+     * otherwise the 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 dlopenExtPath,
+                                                    long loadAddress,
+                                                    LibInfo libInfo);
+
+    /**
+     * Native method used to create a shared RELRO section.
+     * Creates a shared RELRO file for the given library. Done by loading a
+     * a new temporary library at the specified address, saving the RELRO section
+     * from it, then unloading.
+     *
+     * @param dlopenExtPath For load from APK, the path to the enclosing
+     * zipfile concatenated with "!/" and the path to the library within the zipfile;
+     * otherwise the platform specific library name (e.g. libfoo.so).
+     * @param loadAddress load address, which can be different from the one
+     * used to load the library in the current process!
+     * @param relroPath Path to the shared RELRO file for this library.
+     * @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 dlopenExtPath,
+                                                          long loadAddress,
+                                                          String relroPath,
+                                                          LibInfo libInfo);
+}
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
index 2f4356b..96fc4fe 100644
--- a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
+++ b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
@@ -4,8 +4,8 @@
 
 package org.chromium.base.metrics;
 
-import org.chromium.base.JNINamespace;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.JNINamespace;
 
 import java.util.concurrent.TimeUnit;
 
@@ -64,6 +64,16 @@
 
     /**
      * Records a sample in a count histogram. This is the Java equivalent of the
+     * UMA_HISTOGRAM_COUNTS_1000 C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, at least 1 and at most 999
+     */
+    public static void recordCount1000Histogram(String name, int sample) {
+        recordCustomCountHistogram(name, sample, 1, 1000, 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
@@ -78,6 +88,21 @@
     }
 
     /**
+     * Records a sample in a linear histogram. This is the Java equivalent for using
+     * base::LinearHistogram.
+     * @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, should be at least 1.
+     * @param max upper bounds for expected sample values
+     * @param numBuckets the number of buckets
+     */
+    public static void recordLinearCountHistogram(
+            String name, int sample, int min, int max, int numBuckets) {
+        nativeRecordLinearCountHistogram(
+                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
@@ -170,6 +195,8 @@
             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 nativeRecordLinearCountHistogram(
+            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);
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java b/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java
index d7cc32c..06004d6 100644
--- a/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java
+++ b/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java
@@ -4,8 +4,8 @@
 
 package org.chromium.base.metrics;
 
-import org.chromium.base.JNINamespace;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.JNINamespace;
 
 /**
  * Java API for recording UMA actions.
diff --git a/base/android/java/templates/ChromiumMultiDex.template b/base/android/java/templates/ChromiumMultiDex.template
new file mode 100644
index 0000000..441294c
--- /dev/null
+++ b/base/android/java/templates/ChromiumMultiDex.template
@@ -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.
+
+package org.chromium.base.multidex;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Process;
+import android.support.multidex.MultiDex;
+
+import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ *  Performs multidex installation for non-isolated processes.
+ */
+public class ChromiumMultiDex {
+
+    private static final String TAG = "base_multidex";
+
+    /**
+     * Suffix for the meta-data tag in the AndroidManifext.xml that determines whether loading
+     * secondary dexes should be skipped for a given process name.
+     */
+    private static final String IGNORE_MULTIDEX_KEY = ".ignore_multidex";
+
+    /**
+     *  Installs secondary dexes if possible/necessary.
+     *
+     *  Isolated processes (e.g. renderer processes) can't load secondary dex files on
+     *  K and below, so we don't even try in that case.
+     *
+     *  In release builds, this is a no-op because:
+     *    - multidex isn't necessary in release builds because we run proguard there and
+     *      thus aren't threatening to hit the dex limit; and
+     *    - calling MultiDex.install, even in the absence of secondary dexes, causes a
+     *      significant regression in start-up time (crbug.com/525695).
+     *
+     *  @param context The application context.
+     */
+    @VisibleForTesting
+#if defined(MULTIDEX_CONFIGURATION_Debug)
+    public static void install(Context context) {
+        // TODO(jbudorick): Back out this version check once support for K & below works.
+        // http://crbug.com/512357
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP
+                && !shouldInstallMultiDex(context)) {
+            Log.i(TAG, "Skipping multidex installation: not needed for process.");
+        } else {
+            MultiDex.install(context);
+            Log.i(TAG, "Completed multidex installation.");
+        }
+    }
+
+    private static String getProcessName(Context context) {
+        try {
+            String currentProcessName = null;
+            int pid = android.os.Process.myPid();
+
+            ActivityManager manager =
+                    (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+            for (RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
+                if (processInfo.pid == pid) {
+                    currentProcessName = processInfo.processName;
+                    break;
+                }
+            }
+
+            return currentProcessName;
+        } catch (SecurityException ex) {
+            return null;
+        }
+    }
+
+    // Determines whether MultiDex should be installed for the current process.  Isolated
+    // Processes should skip MultiDex as they can not actually access the files on disk.
+    // Privileged processes need ot have all of their dependencies in the MainDex for
+    // performance reasons. 
+    private static boolean shouldInstallMultiDex(Context context) {
+        try {
+            Method isIsolatedMethod =
+                    android.os.Process.class.getMethod("isIsolated");
+            Object retVal = isIsolatedMethod.invoke(null);
+            if (retVal != null && retVal instanceof Boolean && ((Boolean) retVal)) {
+                return false;
+            }
+        } catch (IllegalAccessException | IllegalArgumentException
+                | InvocationTargetException | NoSuchMethodException e) {
+            // Ignore and fall back to checking the app processes.
+        }
+
+        String currentProcessName = getProcessName(context);
+        if (currentProcessName == null) return true;
+        
+        PackageManager packageManager = context.getPackageManager();
+        try {
+            ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(),
+                    PackageManager.GET_META_DATA);
+            return !appInfo.metaData.getBoolean(currentProcessName + IGNORE_MULTIDEX_KEY, false);
+        } catch (PackageManager.NameNotFoundException e) {
+            return true;
+        }
+    }
+#else
+    public static void install(Context context) {
+    }
+#endif
+
+}
diff --git a/base/android/java_handler_thread.cc b/base/android/java_handler_thread.cc
index 117971e..0f410b6 100644
--- a/base/android/java_handler_thread.cc
+++ b/base/android/java_handler_thread.cc
@@ -21,7 +21,7 @@
   JNIEnv* env = base::android::AttachCurrentThread();
 
   java_thread_.Reset(Java_JavaHandlerThread_create(
-      env, ConvertUTF8ToJavaString(env, name).Release()));
+      env, ConvertUTF8ToJavaString(env, name).obj()));
 }
 
 JavaHandlerThread::~JavaHandlerThread() {
@@ -55,7 +55,8 @@
   shutdown_event.Wait();
 }
 
-void JavaHandlerThread::InitializeThread(JNIEnv* env, jobject obj,
+void JavaHandlerThread::InitializeThread(JNIEnv* env,
+                                         const JavaParamRef<jobject>& obj,
                                          jlong event) {
   // TYPE_JAVA to get the Android java style message loop.
   message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_JAVA));
@@ -63,8 +64,10 @@
   reinterpret_cast<base::WaitableEvent*>(event)->Signal();
 }
 
-void JavaHandlerThread::StopThread(JNIEnv* env, jobject obj, jlong event) {
-  static_cast<MessageLoopForUI*>(message_loop_.get())->Quit();
+void JavaHandlerThread::StopThread(JNIEnv* env,
+                                   const JavaParamRef<jobject>& obj,
+                                   jlong event) {
+  static_cast<MessageLoopForUI*>(message_loop_.get())->QuitWhenIdle();
   reinterpret_cast<base::WaitableEvent*>(event)->Signal();
 }
 
diff --git a/base/android/java_handler_thread.h b/base/android/java_handler_thread.h
index c9a2c02..07715a8 100644
--- a/base/android/java_handler_thread.h
+++ b/base/android/java_handler_thread.h
@@ -33,8 +33,12 @@
 
   // 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);
+  void InitializeThread(JNIEnv* env,
+                        const JavaParamRef<jobject>& obj,
+                        jlong event);
+  void StopThread(JNIEnv* env,
+                  const JavaParamRef<jobject>& obj,
+                  jlong event);
 
   static bool RegisterBindings(JNIEnv* env);
 
diff --git a/base/android/javatests/src/org/chromium/base/ObserverListTest.java b/base/android/javatests/src/org/chromium/base/ObserverListTest.java
index 973682b..94a9c71 100644
--- a/base/android/javatests/src/org/chromium/base/ObserverListTest.java
+++ b/base/android/javatests/src/org/chromium/base/ObserverListTest.java
@@ -9,6 +9,7 @@
 
 import org.chromium.base.test.util.Feature;
 
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
@@ -70,7 +71,9 @@
         }
     }
 
+    @SuppressWarnings("ElementsCountedInLoop")
     private static <T> int getSizeOfIterable(Iterable<T> iterable) {
+        if (iterable instanceof Collection<?>) return ((Collection<?>) iterable).size();
         int num = 0;
         for (T el : iterable) num++;
         return num;
diff --git a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
index 24af056..6b1888c 100644
--- a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
+++ b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
@@ -20,7 +20,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
+        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER)
+                .ensureInitialized(getInstrumentation().getTargetContext());
         RecordHistogram.initialize();
     }
 
@@ -156,4 +157,37 @@
         assertEquals(1, oneCount.getDelta());
         assertEquals(1, twoCount.getDelta());
     }
+
+    /**
+     * Tests recording of linear count histograms.
+     */
+    @SmallTest
+    public void testRecordLinearCountHistogram() {
+        String histogram = "HelloWorld.LinearCountMetric";
+        HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
+        HistogramDelta oneCount = new HistogramDelta(histogram, 1);
+        HistogramDelta twoCount = new HistogramDelta(histogram, 2);
+        final int min = 1;
+        final int max = 3;
+        final int numBuckets = 4;
+
+        assertEquals(0, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordLinearCountHistogram(histogram, 0, min, max, numBuckets);
+        assertEquals(1, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordLinearCountHistogram(histogram, 0, min, max, numBuckets);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordLinearCountHistogram(histogram, 2, min, max, numBuckets);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(1, twoCount.getDelta());
+    }
 }
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
index 5416be3..26a266d 100644
--- a/base/android/jni_android.cc
+++ b/base/android/jni_android.cc
@@ -20,10 +20,6 @@
 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;
@@ -70,7 +66,7 @@
 }
 
 void InitVM(JavaVM* vm) {
-  DCHECK(!g_jvm);
+  DCHECK(!g_jvm || g_jvm == vm);
   g_jvm = vm;
 }
 
@@ -78,15 +74,6 @@
   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());
@@ -105,11 +92,6 @@
   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()) {
@@ -143,8 +125,8 @@
     JNIEnv* env,
     const char* class_name,
     base::subtle::AtomicWord* atomic_class_id) {
-  COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jclass),
-                 AtomicWord_SmallerThan_jMethodID);
+  static_assert(sizeof(subtle::AtomicWord) >= sizeof(jclass),
+                "AtomicWord can't be smaller than jclass");
   subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_class_id);
   if (value)
     return reinterpret_cast<jclass>(value);
@@ -188,8 +170,8 @@
                             const char* method_name,
                             const char* jni_signature,
                             base::subtle::AtomicWord* atomic_method_id) {
-  COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID),
-                 AtomicWord_SmallerThan_jMethodID);
+  static_assert(sizeof(subtle::AtomicWord) >= sizeof(jmethodID),
+                "AtomicWord can't be smaller than jMethodID");
   subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id);
   if (value)
     return reinterpret_cast<jmethodID>(value);
diff --git a/base/android/jni_android.h b/base/android/jni_android.h
index 9df9041..909e3da 100644
--- a/base/android/jni_android.h
+++ b/base/android/jni_android.h
@@ -47,19 +47,12 @@
 // 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().
+// Initializes the global JVM.
 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
@@ -69,11 +62,6 @@
     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).
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
index 1bbc669..e4f3f0b 100644
--- a/base/android/jni_array.cc
+++ b/base/android/jni_array.cc
@@ -25,8 +25,9 @@
 
 }  // namespace
 
-ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
-    JNIEnv* env, const uint8* bytes, size_t len) {
+ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(JNIEnv* env,
+                                               const uint8_t* bytes,
+                                               size_t len) {
   jbyteArray byte_array = env->NewByteArray(len);
   CheckException(env);
   DCHECK(byte_array);
@@ -38,6 +39,12 @@
   return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
 }
 
+ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+    JNIEnv* env,
+    const std::vector<uint8_t>& bytes) {
+  return ToJavaByteArray(env, bytes.data(), bytes.size());
+}
+
 ScopedJavaLocalRef<jintArray> ToJavaIntArray(
     JNIEnv* env, const int* ints, size_t len) {
   jintArray int_array = env->NewIntArray(len);
@@ -56,8 +63,9 @@
   return ToJavaIntArray(env, ints.data(), ints.size());
 }
 
-ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
-    JNIEnv* env, const int64* longs, size_t len) {
+ScopedJavaLocalRef<jlongArray> ToJavaLongArray(JNIEnv* env,
+                                               const int64_t* longs,
+                                               size_t len) {
   jlongArray long_array = env->NewLongArray(len);
   CheckException(env);
   DCHECK(long_array);
@@ -69,9 +77,10 @@
   return ScopedJavaLocalRef<jlongArray>(env, long_array);
 }
 
-// Returns a new Java long array converted from the given int64 array.
+// Returns a new Java long array converted from the given int64_t array.
 BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
-    JNIEnv* env, const std::vector<int64>& longs) {
+    JNIEnv* env,
+    const std::vector<int64_t>& longs) {
   return ToJavaLongArray(env, longs.data(), longs.size());
 }
 
@@ -83,8 +92,8 @@
   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());
+    ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(
+        env, reinterpret_cast<const uint8_t*>(v[i].data()), v[i].length());
     env->SetObjectArrayElement(joa, i, byte_array.obj());
   }
   return ScopedJavaLocalRef<jobjectArray>(env, joa);
@@ -150,7 +159,7 @@
 
 void AppendJavaByteArrayToByteVector(JNIEnv* env,
                                      jbyteArray byte_array,
-                                     std::vector<uint8>* out) {
+                                     std::vector<uint8_t>* out) {
   DCHECK(out);
   if (!byte_array)
     return;
@@ -165,7 +174,7 @@
 
 void JavaByteArrayToByteVector(JNIEnv* env,
                                jbyteArray byte_array,
-                               std::vector<uint8>* out) {
+                               std::vector<uint8_t>* out) {
   DCHECK(out);
   DCHECK(byte_array);
   out->clear();
@@ -185,6 +194,16 @@
   env->GetIntArrayRegion(int_array, 0, len, &(*out)[0]);
 }
 
+void JavaLongArrayToInt64Vector(JNIEnv* env,
+                                jlongArray long_array,
+                                std::vector<int64_t>* out) {
+  DCHECK(out);
+  std::vector<jlong> temp;
+  JavaLongArrayToLongVector(env, long_array, &temp);
+  out->resize(0);
+  out->insert(out->begin(), temp.begin(), temp.end());
+}
+
 void JavaLongArrayToLongVector(JNIEnv* env,
                                jlongArray long_array,
                                std::vector<jlong>* out) {
@@ -219,11 +238,25 @@
         env, static_cast<jbyteArray>(
             env->GetObjectArrayElement(array, i)));
     jsize bytes_len = env->GetArrayLength(bytes_array.obj());
-    jbyte* bytes = env->GetByteArrayElements(bytes_array.obj(), NULL);
+    jbyte* bytes = env->GetByteArrayElements(bytes_array.obj(), nullptr);
     (*out)[i].assign(reinterpret_cast<const char*>(bytes), bytes_len);
     env->ReleaseByteArrayElements(bytes_array.obj(), bytes, JNI_ABORT);
   }
 }
 
+void JavaArrayOfIntArrayToIntVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::vector<int>>* out) {
+  DCHECK(out);
+  size_t len = SafeGetArrayLength(env, array);
+  out->resize(len);
+  for (size_t i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jintArray> int_array(
+        env, static_cast<jintArray>(env->GetObjectArrayElement(array, i)));
+    JavaIntArrayToIntVector(env, int_array.obj(), &((*out)[i]));
+  }
+}
+
 }  // namespace android
 }  // namespace base
diff --git a/base/android/jni_array.h b/base/android/jni_array.h
index 0d7ec2e..86e63c5 100644
--- a/base/android/jni_array.h
+++ b/base/android/jni_array.h
@@ -6,19 +6,24 @@
 #define BASE_ANDROID_JNI_ARRAY_H_
 
 #include <jni.h>
+#include <stdint.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_t* bytes,
+                                                           size_t len);
+
 BASE_EXPORT ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
-    JNIEnv* env, const uint8* bytes, size_t len);
+    JNIEnv* env,
+    const std::vector<uint8_t>& bytes);
 
 // Returns a new Java int array converted from the given int array.
 BASE_EXPORT ScopedJavaLocalRef<jintArray> ToJavaIntArray(
@@ -28,11 +33,13 @@
     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 int64_t* longs,
+                                                           size_t len);
 
 BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
-    JNIEnv* env, const std::vector<int64>& longs);
+    JNIEnv* env,
+    const std::vector<int64_t>& longs);
 
 // Returns a array of Java byte array converted from |v|.
 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
@@ -56,16 +63,14 @@
     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);
+BASE_EXPORT void AppendJavaByteArrayToByteVector(JNIEnv* env,
+                                                 jbyteArray byte_array,
+                                                 std::vector<uint8_t>* 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);
+BASE_EXPORT void JavaByteArrayToByteVector(JNIEnv* env,
+                                           jbyteArray byte_array,
+                                           std::vector<uint8_t>* out);
 
 // Replaces the content of |out| with the Java ints in |int_array|.
 BASE_EXPORT void JavaIntArrayToIntVector(
@@ -74,6 +79,11 @@
     std::vector<int>* out);
 
 // Replaces the content of |out| with the Java longs in |long_array|.
+BASE_EXPORT void JavaLongArrayToInt64Vector(JNIEnv* env,
+                                            jlongArray long_array,
+                                            std::vector<int64_t>* out);
+
+// Replaces the content of |out| with the Java longs in |long_array|.
 BASE_EXPORT void JavaLongArrayToLongVector(
     JNIEnv* env,
     jlongArray long_array,
@@ -93,6 +103,13 @@
     jobjectArray array,
     std::vector<std::string>* out);
 
+// Assuming |array| is an int[][] (array of int arrays), replaces the
+// contents of |out| with the corresponding vectors of ints.
+BASE_EXPORT void JavaArrayOfIntArrayToIntVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::vector<int>>* out);
+
 }  // namespace android
 }  // namespace base
 
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc
index 7cb896c..f81014e 100644
--- a/base/android/jni_array_unittest.cc
+++ b/base/android/jni_array_unittest.cc
@@ -12,22 +12,31 @@
 namespace android {
 
 TEST(JniArray, BasicConversions) {
-  const uint8 kBytes[] = { 0, 1, 2, 3 };
+  const uint8_t 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);
+  std::vector<uint8_t> inputVector(kBytes, kBytes + kLen);
+  ScopedJavaLocalRef<jbyteArray> bytesFromVector =
+      ToJavaByteArray(env, inputVector);
+  ASSERT_TRUE(bytesFromVector.obj());
 
-  AppendJavaByteArrayToByteVector(env, bytes.obj(), &vec);
-  EXPECT_EQ(8U, vec.size());
+  std::vector<uint8_t> vectorFromBytes(5);
+  std::vector<uint8_t> vectorFromVector(5);
+  JavaByteArrayToByteVector(env, bytes.obj(), &vectorFromBytes);
+  JavaByteArrayToByteVector(env, bytesFromVector.obj(), &vectorFromVector);
+  EXPECT_EQ(4U, vectorFromBytes.size());
+  EXPECT_EQ(4U, vectorFromVector.size());
+  std::vector<uint8_t> expected_vec(kBytes, kBytes + kLen);
+  EXPECT_EQ(expected_vec, vectorFromBytes);
+  EXPECT_EQ(expected_vec, vectorFromVector);
+
+  AppendJavaByteArrayToByteVector(env, bytes.obj(), &vectorFromBytes);
+  EXPECT_EQ(8U, vectorFromBytes.size());
   expected_vec.insert(expected_vec.end(), kBytes, kBytes + kLen);
-  EXPECT_EQ(expected_vec, vec);
+  EXPECT_EQ(expected_vec, vectorFromBytes);
 }
 
 void CheckIntConversion(
@@ -58,11 +67,10 @@
   CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, vec));
 }
 
-void CheckLongConversion(
-    JNIEnv* env,
-    const int64* long_array,
-    const size_t len,
-    const ScopedJavaLocalRef<jlongArray>& longs) {
+void CheckLongConversion(JNIEnv* env,
+                         const int64_t* long_array,
+                         const size_t len,
+                         const ScopedJavaLocalRef<jlongArray>& longs) {
   ASSERT_TRUE(longs.obj());
 
   jsize java_array_len = env->GetArrayLength(longs.obj());
@@ -76,16 +84,27 @@
 }
 
 TEST(JniArray, LongConversions) {
-  const int64 kLongs[] = { 0, 1, -1, kint64min, kint64max};
+  const int64_t 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);
+  const std::vector<int64_t> vec(kLongs, kLongs + kLen);
   CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, vec));
 }
 
+void CheckIntArrayConversion(JNIEnv* env,
+                             ScopedJavaLocalRef<jintArray> jints,
+                             std::vector<int> int_vector,
+                             const size_t len) {
+  jint value;
+  for (size_t i = 0; i < len; ++i) {
+    env->GetIntArrayRegion(jints.obj(), i, 1, &value);
+    ASSERT_EQ(int_vector[i], value);
+  }
+}
+
 TEST(JniArray, JavaIntArrayToIntVector) {
   const int kInts[] = {0, 1, -1};
   const size_t kLen = arraysize(kInts);
@@ -105,10 +124,61 @@
 
   ASSERT_EQ(static_cast<jsize>(ints.size()), env->GetArrayLength(jints.obj()));
 
-  jint value;
+  CheckIntArrayConversion(env, jints, ints, kLen);
+}
+
+TEST(JniArray, JavaLongArrayToInt64Vector) {
+  const int64_t kInt64s[] = {0LL, 1LL, -1LL};
+  const size_t kLen = arraysize(kInt64s);
+
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kLen));
+  ASSERT_TRUE(jlongs.obj());
+
   for (size_t i = 0; i < kLen; ++i) {
-    env->GetIntArrayRegion(jints.obj(), i, 1, &value);
-    ASSERT_EQ(ints[i], value);
+    jlong j = static_cast<jlong>(kInt64s[i]);
+    env->SetLongArrayRegion(jlongs.obj(), i, 1, &j);
+    ASSERT_FALSE(HasException(env));
+  }
+
+  std::vector<int64_t> int64s;
+  JavaLongArrayToInt64Vector(env, jlongs.obj(), &int64s);
+
+  ASSERT_EQ(static_cast<jsize>(int64s.size()),
+            env->GetArrayLength(jlongs.obj()));
+
+  jlong value;
+  for (size_t i = 0; i < kLen; ++i) {
+    env->GetLongArrayRegion(jlongs.obj(), i, 1, &value);
+    ASSERT_EQ(int64s[i], value);
+    ASSERT_EQ(kInt64s[i], int64s[i]);
+  }
+}
+
+TEST(JniArray, JavaLongArrayToLongVector) {
+  const int64_t kInt64s[] = {0LL, 1LL, -1LL};
+  const size_t kLen = arraysize(kInt64s);
+
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kLen));
+  ASSERT_TRUE(jlongs.obj());
+
+  for (size_t i = 0; i < kLen; ++i) {
+    jlong j = static_cast<jlong>(kInt64s[i]);
+    env->SetLongArrayRegion(jlongs.obj(), i, 1, &j);
+    ASSERT_FALSE(HasException(env));
+  }
+
+  std::vector<jlong> jlongs_vector;
+  JavaLongArrayToLongVector(env, jlongs.obj(), &jlongs_vector);
+
+  ASSERT_EQ(static_cast<jsize>(jlongs_vector.size()),
+            env->GetArrayLength(jlongs.obj()));
+
+  jlong value;
+  for (size_t i = 0; i < kLen; ++i) {
+    env->GetLongArrayRegion(jlongs.obj(), i, 1, &value);
+    ASSERT_EQ(jlongs_vector[i], value);
   }
 }
 
@@ -155,9 +225,9 @@
   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)));
+    ScopedJavaLocalRef<jbyteArray> byte_array =
+        ToJavaByteArray(env, reinterpret_cast<uint8_t*>(text),
+                        static_cast<size_t>(strlen(text)));
     ASSERT_TRUE(byte_array.obj());
 
     env->SetObjectArrayElement(array.obj(), i, byte_array.obj());
@@ -175,5 +245,49 @@
   }
 }
 
+TEST(JniArray, JavaArrayOfIntArrayToIntVector) {
+  const size_t kNumItems = 4;
+  JNIEnv* env = AttachCurrentThread();
+
+  // Create an int[][] object.
+  ScopedJavaLocalRef<jclass> int_array_clazz(env, env->FindClass("[I"));
+  ASSERT_TRUE(int_array_clazz.obj());
+
+  ScopedJavaLocalRef<jobjectArray> array(
+      env, env->NewObjectArray(kNumItems, int_array_clazz.obj(), nullptr));
+  ASSERT_TRUE(array.obj());
+
+  // Populate int[][] object.
+  const int kInts0[] = {0, 1, -1, kint32min, kint32max};
+  const size_t kLen0 = arraysize(kInts0);
+  ScopedJavaLocalRef<jintArray> int_array0 = ToJavaIntArray(env, kInts0, kLen0);
+  env->SetObjectArrayElement(array.obj(), 0, int_array0.obj());
+
+  const int kInts1[] = {3, 4, 5};
+  const size_t kLen1 = arraysize(kInts1);
+  ScopedJavaLocalRef<jintArray> int_array1 = ToJavaIntArray(env, kInts1, kLen1);
+  env->SetObjectArrayElement(array.obj(), 1, int_array1.obj());
+
+  const int kInts2[] = {};
+  const size_t kLen2 = 0;
+  ScopedJavaLocalRef<jintArray> int_array2 = ToJavaIntArray(env, kInts2, kLen2);
+  env->SetObjectArrayElement(array.obj(), 2, int_array2.obj());
+
+  const int kInts3[] = {16};
+  const size_t kLen3 = arraysize(kInts3);
+  ScopedJavaLocalRef<jintArray> int_array3 = ToJavaIntArray(env, kInts3, kLen3);
+  env->SetObjectArrayElement(array.obj(), 3, int_array3.obj());
+
+  // Convert to std::vector<std::vector<int>>, check the content.
+  std::vector<std::vector<int>> out;
+  JavaArrayOfIntArrayToIntVector(env, array.obj(), &out);
+
+  EXPECT_EQ(kNumItems, out.size());
+  CheckIntArrayConversion(env, int_array0, out[0], kLen0);
+  CheckIntArrayConversion(env, int_array1, out[1], kLen1);
+  CheckIntArrayConversion(env, int_array2, out[2], kLen2);
+  CheckIntArrayConversion(env, int_array3, out[3], kLen3);
+}
+
 }  // namespace android
 }  // namespace base
diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/golden_sample_for_tests_jni.h
index ba7494e..e982609 100644
--- a/base/android/jni_generator/golden_sample_for_tests_jni.h
+++ b/base/android/jni_generator/golden_sample_for_tests_jni.h
@@ -39,61 +39,120 @@
 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,
+
+static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
+    const JavaParamRef<jstring>& param);
+
+static jlong
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeInit(JNIEnv*
+    env, jobject jcaller,
+    jstring param) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller),
+      JavaParamRef<jstring>(env, param));
+}
+
+static void
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeDestroy(JNIEnv*
+    env,
+    jobject jcaller,
     jlong nativeCPPClass) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
-  return native->Destroy(env, jcaller);
+  return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
 }
 
-static jint Method(JNIEnv* env, jobject jcaller,
+static jdouble GetDoubleFunction(JNIEnv* env, const JavaParamRef<jobject>&
+    jcaller);
+
+static jdouble
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetDoubleFunction(JNIEnv*
+    env, jobject jcaller) {
+  return GetDoubleFunction(env, JavaParamRef<jobject>(env, jcaller));
+}
+
+static jfloat GetFloatFunction(JNIEnv* env, const JavaParamRef<jclass>&
+    jcaller);
+
+static jfloat
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetFloatFunction(JNIEnv*
+    env, jclass jcaller) {
+  return GetFloatFunction(env, JavaParamRef<jclass>(env, jcaller));
+}
+
+static void SetNonPODDatatype(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
+    const JavaParamRef<jobject>& rect);
+
+static void
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeSetNonPODDatatype(JNIEnv*
+    env, jobject jcaller,
+    jobject rect) {
+  return SetNonPODDatatype(env, JavaParamRef<jobject>(env, jcaller),
+      JavaParamRef<jobject>(env, rect));
+}
+
+static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, const
+    JavaParamRef<jobject>& jcaller);
+
+static jobject
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetNonPODDatatype(JNIEnv*
+    env, jobject jcaller) {
+  return GetNonPODDatatype(env, JavaParamRef<jobject>(env, jcaller)).Release();
+}
+
+static jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(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);
+  return native->Method(env, JavaParamRef<jobject>(env, jcaller));
 }
 
-static jdouble MethodOtherP0(JNIEnv* env, jobject jcaller,
+static jdouble
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethodOtherP0(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);
+  return native->MethodOtherP0(env, JavaParamRef<jobject>(env, jcaller));
 }
 
-static void AddStructB(JNIEnv* env, jobject jcaller,
+static void
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeAddStructB(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);
+  return native->AddStructB(env, JavaParamRef<jobject>(env, jcaller),
+      JavaParamRef<jobject>(env, b));
 }
 
-static void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject jcaller,
+static void
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeIterateAndDoSomethingWithStructB(JNIEnv*
+    env,
+    jobject jcaller,
     jlong nativeCPPClass) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "IterateAndDoSomethingWithStructB");
-  return native->IterateAndDoSomethingWithStructB(env, jcaller);
+  return native->IterateAndDoSomethingWithStructB(env,
+      JavaParamRef<jobject>(env, jcaller));
 }
 
-static jstring ReturnAString(JNIEnv* env, jobject jcaller,
+static jstring
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeReturnAString(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();
+  return native->ReturnAString(env, JavaParamRef<jobject>(env,
+      jcaller)).Release();
 }
 
 static base::subtle::AtomicWord g_SampleForTests_javaMethod = 0;
@@ -192,8 +251,8 @@
 }
 
 static base::subtle::AtomicWord g_InnerStructA_create = 0;
-static base::android::ScopedJavaLocalRef<jobject>
-    Java_InnerStructA_create(JNIEnv* env, jlong l,
+static ScopedJavaLocalRef<jobject> Java_InnerStructA_create(JNIEnv* env, jlong
+    l,
     JniIntWrapper i,
     jstring s) {
   /* Must call RegisterNativesImpl()  */
@@ -217,7 +276,7 @@
       env->CallStaticObjectMethod(InnerStructA_clazz(env),
           method_id, l, as_jint(i), s);
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_SampleForTests_addStructA = 0;
@@ -291,8 +350,8 @@
 }
 
 static base::subtle::AtomicWord g_InnerStructB_getValue = 0;
-static base::android::ScopedJavaLocalRef<jstring>
-    Java_InnerStructB_getValue(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jstring> Java_InnerStructB_getValue(JNIEnv* env,
+    jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       InnerStructB_clazz(env), NULL);
@@ -311,7 +370,7 @@
       static_cast<jstring>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+  return ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 // Step 3: RegisterNatives.
@@ -321,55 +380,77 @@
 "("
 "Ljava/lang/String;"
 ")"
-"J", reinterpret_cast<void*>(Init) },
+"J",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeInit)
+    },
     { "nativeDestroy",
 "("
 "J"
 ")"
-"V", reinterpret_cast<void*>(Destroy) },
+"V",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeDestroy)
+    },
     { "nativeGetDoubleFunction",
 "("
 ")"
-"D", reinterpret_cast<void*>(GetDoubleFunction) },
+"D",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetDoubleFunction)
+    },
     { "nativeGetFloatFunction",
 "("
 ")"
-"F", reinterpret_cast<void*>(GetFloatFunction) },
+"F",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetFloatFunction)
+    },
     { "nativeSetNonPODDatatype",
 "("
 "Landroid/graphics/Rect;"
 ")"
-"V", reinterpret_cast<void*>(SetNonPODDatatype) },
+"V",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeSetNonPODDatatype)
+    },
     { "nativeGetNonPODDatatype",
 "("
 ")"
-"Ljava/lang/Object;", reinterpret_cast<void*>(GetNonPODDatatype) },
+"Ljava/lang/Object;",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetNonPODDatatype)
+    },
     { "nativeMethod",
 "("
 "J"
 ")"
-"I", reinterpret_cast<void*>(Method) },
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod)
+    },
     { "nativeMethodOtherP0",
 "("
 "J"
 ")"
-"D", reinterpret_cast<void*>(MethodOtherP0) },
+"D",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethodOtherP0)
+    },
     { "nativeAddStructB",
 "("
 "J"
 "Lorg/chromium/example/jni_generator/SampleForTests$InnerStructB;"
 ")"
-"V", reinterpret_cast<void*>(AddStructB) },
+"V",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeAddStructB)
+    },
     { "nativeIterateAndDoSomethingWithStructB",
 "("
 "J"
 ")"
-"V", reinterpret_cast<void*>(IterateAndDoSomethingWithStructB) },
+"V",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeIterateAndDoSomethingWithStructB)
+    },
     { "nativeReturnAString",
 "("
 "J"
 ")"
-"Ljava/lang/String;", reinterpret_cast<void*>(ReturnAString) },
+"Ljava/lang/String;",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeReturnAString)
+    },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
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
index 89bee99..c1fc667 100644
--- 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
@@ -6,11 +6,11 @@
 
 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.CalledByNative;
 import org.chromium.base.annotations.CalledByNativeUnchecked;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeClassQualifiedName;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -92,7 +92,7 @@
 @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.
+    // calling out a nativeInit() function. Replace "CPPClass" with your particular class name!
     long mNativeCPPObject;
 
     // You can define methods and attributes on the java class just like any other.
@@ -101,7 +101,7 @@
     }
 
     public void startExample() {
-        // Calls native code and holds a pointer to the C++ class.
+        // Calls C++ Init(...) method and holds a pointer to the C++ class.
         mNativeCPPObject = nativeInit("myParam");
     }
 
@@ -125,7 +125,7 @@
     // 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)
+    // Java_Example_javaMethod(JNIEnv* env, jobject caller, 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) {
@@ -177,7 +177,7 @@
     // 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);
+    // static jint Init(JNIEnv* env, jobject caller);
     // 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
@@ -187,14 +187,15 @@
 
     // 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.
+    // native prefixes stripped).
+    //
+    // The |nativeCPPClass| is automatically cast to type CPPClass*, in order to obtain the object
+    // on
+    // which to invoke the member function. Replace "CPPClass" with your particular class name!
     private native void nativeDestroy(long nativeCPPClass);
 
     // This declares a C++ function which the application code must implement:
-    // static jdouble GetDoubleFunction(JNIEnv* env, jobject obj);
+    // static jdouble GetDoubleFunction(JNIEnv* env, jobject caller);
     // The jobject parameter refers back to this java side object instance.
     private native double nativeGetDoubleFunction();
 
@@ -203,21 +204,19 @@
     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
+    // 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);
+    // static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject caller);
     // 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.
+    // and call its Method member function. Replace "CPPClass" with your particular class name!
     private native int nativeMethod(long nativeCPPClass);
 
     // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from the
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index fd03f0e..5d262c8 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -113,8 +113,10 @@
   java_type_map = {
       'void': 'void',
       'String': 'jstring',
+      'Throwable': 'jthrowable',
       'java/lang/String': 'jstring',
       'java/lang/Class': 'jclass',
+      'java/lang/Throwable': 'jthrowable',
   }
 
   if java_type in java_pod_type_map:
@@ -133,6 +135,19 @@
     return 'jobject'
 
 
+def WrapCTypeForDeclaration(c_type):
+  """Wrap the C datatype in a JavaRef if required."""
+  if re.match(RE_SCOPED_JNI_TYPES, c_type):
+    return 'const JavaParamRef<' + c_type + '>&'
+  else:
+    return c_type
+
+
+def JavaDataTypeToCForDeclaration(java_type):
+  """Returns a JavaRef-wrapped C datatype for the given java type."""
+  return WrapCTypeForDeclaration(JavaDataTypeToC(java_type))
+
+
 def JavaDataTypeToCForCalledByNativeParam(java_type):
   """Returns a C datatype to be when calling from native."""
   if java_type == 'int':
@@ -236,6 +251,9 @@
         'Ljava/lang/Object',
         'Ljava/lang/String',
         'Ljava/lang/Class',
+        'Ljava/lang/CharSequence',
+        'Ljava/lang/Runnable',
+        'Ljava/lang/Throwable',
     ]
 
     prefix = ''
@@ -427,6 +445,8 @@
 def GetStaticCastForReturnType(return_type):
   type_map = { 'String' : 'jstring',
                'java/lang/String' : 'jstring',
+               'Throwable': 'jthrowable',
+               'java/lang/Throwable': 'jthrowable',
                'boolean[]': 'jbooleanArray',
                'byte[]': 'jbyteArray',
                'char[]': 'jcharArray',
@@ -520,9 +540,9 @@
   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 the JNI types that should be wrapped in a JavaRef.
+RE_SCOPED_JNI_TYPES = re.compile('jobject|jclass|jstring|jthrowable|.*Array')
+
 
 # Regex to match a string like "@CalledByNative public void foo(int bar)".
 RE_CALLED_BY_NATIVE = re.compile(
@@ -761,7 +781,6 @@
 }  // namespace
 
 $OPEN_NAMESPACE
-$FORWARD_DECLARATIONS
 
 $CONSTANT_FIELDS
 
@@ -780,7 +799,6 @@
         '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(),
@@ -813,15 +831,6 @@
       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 ''
@@ -835,15 +844,11 @@
     """Returns the code corresponding to method stubs."""
     ret = []
     for native in self.natives:
-      if native.type == 'method':
-        ret += [self.GetNativeMethodStubString(native)]
+      ret += [self.GetNativeStub(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):
@@ -1012,18 +1017,36 @@
       return '\n'.join(all_namespaces) + '\n'
     return ''
 
-  def GetJNIFirstParam(self, native):
-    ret = []
+  def GetJNIFirstParamType(self, native):
     if native.type == 'method':
-      ret = ['jobject jcaller']
+      return 'jobject'
     elif native.type == 'function':
       if native.static:
-        ret = ['jclass jcaller']
+        return 'jclass'
       else:
-        ret = ['jobject jcaller']
-    return ret
+        return 'jobject'
+
+  def GetJNIFirstParam(self, native, for_declaration):
+    c_type = self.GetJNIFirstParamType(native)
+    if for_declaration:
+      c_type = WrapCTypeForDeclaration(c_type)
+    return [c_type + ' jcaller']
 
   def GetParamsInDeclaration(self, native):
+    """Returns the params for the forward declaration.
+
+    Args:
+      native: the native dictionary describing the method.
+
+    Returns:
+      A string containing the params.
+    """
+    return ',\n    '.join(self.GetJNIFirstParam(native, True) +
+                          [JavaDataTypeToCForDeclaration(param.datatype) + ' ' +
+                           param.name
+                           for param in native.params])
+
+  def GetParamsInStub(self, native):
     """Returns the params for the stub declaration.
 
     Args:
@@ -1032,7 +1055,7 @@
     Returns:
       A string containing the params.
     """
-    return ',\n    '.join(self.GetJNIFirstParam(native) +
+    return ',\n    '.join(self.GetJNIFirstParam(native, False) +
                           [JavaDataTypeToC(param.datatype) + ' ' +
                            param.name
                            for param in native.params])
@@ -1050,90 +1073,94 @@
       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.
+      A string with the stub function name (used by the JVM).
     """
-    if self.options.native_exports:
-      template = Template("Java_${JAVA_NAME}_native${NAME}")
+    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
+    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)}
+    values = {'NAME': native.name,
+              'JAVA_NAME': java_name}
     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}) {"""
+  def GetJavaParamRefForCall(self, c_type, name):
+    return Template('JavaParamRef<${TYPE}>(env, ${NAME})').substitute({
+        'TYPE': c_type,
+        'NAME': name,
+    })
+
+  def GetJNIFirstParamForCall(self, native):
+    c_type = self.GetJNIFirstParamType(native)
+    return [self.GetJavaParamRefForCall(c_type, 'jcaller')]
+
+  def GetNativeStub(self, native):
+    is_method = native.type == 'method'
+
+    if is_method:
+      params = native.params[1:]
     else:
-      template_str = """\
-static ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
-    template_str += """
+      params = native.params
+    params_in_call = []
+    if not self.options.pure_native_methods:
+      params_in_call = ['env'] + self.GetJNIFirstParamForCall(native)
+    for p in params:
+      c_type = JavaDataTypeToC(p.datatype)
+      if re.match(RE_SCOPED_JNI_TYPES, c_type):
+        params_in_call.append(self.GetJavaParamRefForCall(c_type, p.name))
+      else:
+        params_in_call.append(p.name)
+    params_in_call = ', '.join(params_in_call)
+
+    if self.options.native_exports:
+      stub_visibility = 'extern "C" __attribute__((visibility("default")))\n'
+    else:
+      stub_visibility = 'static '
+    return_type = return_declaration = JavaDataTypeToC(native.return_type)
+    post_call = ''
+    if re.match(RE_SCOPED_JNI_TYPES, return_type):
+      post_call = '.Release()'
+      return_declaration = 'ScopedJavaLocalRef<' + return_type + '>'
+    values = {
+        'RETURN': return_type,
+        'RETURN_DECLARATION': return_declaration,
+        'NAME': native.name,
+        'PARAMS': self.GetParamsInDeclaration(native),
+        'PARAMS_IN_STUB': self.GetParamsInStub(native),
+        'PARAMS_IN_CALL': params_in_call,
+        'POST_CALL': post_call,
+        'STUB_NAME': self.GetStubName(native),
+        'STUB_VISIBILITY': stub_visibility,
+    }
+
+    if is_method:
+      optional_error_return = JavaReturnValueToC(native.return_type)
+      if optional_error_return:
+        optional_error_return = ', ' + optional_error_return
+      values.update({
+          'OPTIONAL_ERROR_RETURN': optional_error_return,
+          'PARAM0_NAME': native.params[0].name,
+          'P0_TYPE': native.p0_type,
+      })
+      template = Template("""\
+${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env,
+    ${PARAMS_IN_STUB}) {
   ${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};
 }
-"""
+""")
+    else:
+      template = Template("""
+static ${RETURN_DECLARATION} ${NAME}(JNIEnv* env, ${PARAMS});
 
-    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:]])
+${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
+  return ${NAME}(${PARAMS_IN_CALL})${POST_CALL};
+}
+""")
 
-    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):
@@ -1177,8 +1204,8 @@
     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 + '>'
+      if re.match(RE_SCOPED_JNI_TYPES, return_type):
+        return_type = 'ScopedJavaLocalRef<' + return_type + '>'
         return_clause = 'return ' + return_type + '(env, ret);'
       else:
         return_clause = 'return ret;'
@@ -1443,7 +1470,7 @@
     with file(output_file, 'w') as f:
       f.write(content)
   else:
-    print output
+    print content
 
 
 def GetScriptName():
diff --git a/base/android/jni_generator/jni_generator_helper.h b/base/android/jni_generator/jni_generator_helper.h
index b9736e1..1fdc4ee 100644
--- a/base/android/jni_generator/jni_generator_helper.h
+++ b/base/android/jni_generator/jni_generator_helper.h
@@ -36,5 +36,6 @@
 }  // namespace jni_generator
 
 using base::android::ScopedJavaLocalRef;
+using base::android::JavaParamRef;
 
 #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
index 6014847..22e54cf 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -149,6 +149,7 @@
     private native void nativeGotOrientation(
             int nativeDataFetcherImplAndroid,
             double alpha, double beta, double gamma);
+    private static native Throwable nativeMessWithJavaException(Throwable e);
     """
     jni_generator.JniParams.SetFullyQualifiedClass(
         'org/chromium/example/jni_generator/SampleForTests')
@@ -272,6 +273,11 @@
                      java_class_name=None,
                      type='method',
                      p0_type='content::DataFetcherImplAndroid'),
+        NativeMethod(return_type='Throwable', static=True,
+                     name='MessWithJavaException',
+                     params=[Param(datatype='Throwable', name='e')],
+                     java_class_name=None,
+                     type='function')
     ]
     self.assertListEquals(golden_natives, natives)
     h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
@@ -896,8 +902,8 @@
 
 import java.util.ArrayList;
 
-import org.chromium.base.CalledByNative;
-import org.chromium.base.JNINamespace;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
 import org.chromium.content.app.ContentMain;
 import org.chromium.content.browser.SandboxedProcessConnection;
 import org.chromium.content.common.ISandboxedProcessCallback;
@@ -1085,29 +1091,6 @@
           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;
diff --git a/base/android/jni_generator/sample_for_tests.cc b/base/android/jni_generator/sample_for_tests.cc
index 6707742..3fca39a 100644
--- a/base/android/jni_generator/sample_for_tests.cc
+++ b/base/android/jni_generator/sample_for_tests.cc
@@ -7,16 +7,22 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
-#include "jni/SampleForTests_jni.h"
-
+// Generated file for JNI bindings from C++ to Java @CalledByNative methods.
+// Only to be included in one .cc file.
+// Name is based on the java file name: *.java -> jni/*_jni.h
+#include "jni/SampleForTests_jni.h"  // Generated by JNI.
 
 using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
 using base::android::ScopedJavaLocalRef;
 
 namespace base {
 namespace android {
 
-jdouble CPPClass::InnerClass::MethodOtherP0(JNIEnv* env, jobject obj) {
+jdouble CPPClass::InnerClass::MethodOtherP0(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& caller) {
   return 0.0;
 }
 
@@ -26,22 +32,31 @@
 CPPClass::~CPPClass() {
 }
 
-void CPPClass::Destroy(JNIEnv* env, jobject obj) {
+// static
+bool CPPClass::RegisterJNI(JNIEnv* env) {
+  return RegisterNativesImpl(env);  // Generated in SampleForTests_jni.h
+}
+
+void CPPClass::Destroy(JNIEnv* env, const JavaParamRef<jobject>& caller) {
   delete this;
 }
 
-jint CPPClass::Method(JNIEnv* env, jobject obj) {
+jint CPPClass::Method(JNIEnv* env, const JavaParamRef<jobject>& caller) {
   return 0;
 }
 
-void CPPClass::AddStructB(JNIEnv* env, jobject obj, jobject structb) {
+void CPPClass::AddStructB(JNIEnv* env,
+                          const JavaParamRef<jobject>& caller,
+                          const JavaParamRef<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) {
+void CPPClass::IterateAndDoSomethingWithStructB(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& caller) {
   // Iterate over the elements and do something with them.
   for (std::map<long, std::string>::const_iterator it = map_.begin();
        it != map_.end(); ++it) {
@@ -51,31 +66,35 @@
   map_.clear();
 }
 
-base::android::ScopedJavaLocalRef<jstring> CPPClass::ReturnAString(
-    JNIEnv* env, jobject obj) {
-  base::android::ScopedJavaLocalRef<jstring> ret = ConvertUTF8ToJavaString(
-      env, "test");
-  return ret;
+ScopedJavaLocalRef<jstring> CPPClass::ReturnAString(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& caller) {
+  return ConvertUTF8ToJavaString(env, "test");
 }
 
 // Static free functions declared and called directly from java.
-static jlong Init(JNIEnv* env, jobject obj, jstring param) {
+static jlong Init(JNIEnv* env,
+                  const JavaParamRef<jobject>& caller,
+                  const JavaParamRef<jstring>& param) {
   return 0;
 }
 
-static jdouble GetDoubleFunction(JNIEnv*, jobject) {
+static jdouble GetDoubleFunction(JNIEnv*, const JavaParamRef<jobject>&) {
   return 0;
 }
 
-static jfloat GetFloatFunction(JNIEnv*, jclass) {
+static jfloat GetFloatFunction(JNIEnv*, const JavaParamRef<jclass>&) {
   return 0;
 }
 
-static void SetNonPODDatatype(JNIEnv*, jobject, jobject) {
-}
+static void SetNonPODDatatype(JNIEnv*,
+                              const JavaParamRef<jobject>&,
+                              const JavaParamRef<jobject>&) {}
 
-static jobject GetNonPODDatatype(JNIEnv*, jobject) {
-  return NULL;
+static ScopedJavaLocalRef<jobject> GetNonPODDatatype(
+    JNIEnv*,
+    const JavaParamRef<jobject>&) {
+  return ScopedJavaLocalRef<jobject>();
 }
 
 static jint InnerFunction(JNIEnv*, jclass) {
@@ -103,8 +122,7 @@
     // 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());
+            env, 0, 1, ConvertUTF8ToJavaString(env, "test").obj());
     base::android::Java_SampleForTests_addStructA(
         env, my_java_object, struct_a.obj());
   }
diff --git a/base/android/jni_generator/sample_for_tests.h b/base/android/jni_generator/sample_for_tests.h
index c98cf97..42ba84b 100644
--- a/base/android/jni_generator/sample_for_tests.h
+++ b/base/android/jni_generator/sample_for_tests.h
@@ -20,28 +20,153 @@
 // - 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.
+// Methods are called directly from Java (except RegisterJNI). More
+// documentation in SampleForTests.java
+//
+// For C++ to access Java methods:
+// - GYP Build must be configured to generate bindings:
+//  # ...
+//  'targets': [
+//    {
+//      # An example target that will rely on JNI:
+//      'target_name': 'foo',
+//      'type': '<(component)',
+//      # ... normal sources, defines, deps.
+//      #     For each jni generated .java -> .h header file in foo_jni_headers
+//      #     target there will be a single .cc file here that includes it.
+//      #
+//      # Add deps for JNI:
+//      'conditions': [
+//        ['OS == "android"', {
+//          'dependencies': [
+//            'foo_java',
+//            'foo_jni_headers',
+//          ],
+//        }],
+//      ],
+//    },
+//  ],
+//  # ...
+//  # Create targets for JNI:
+//  'conditions': [
+//    ['OS == "android"', {
+//      'targets': [
+//        {
+//          'target_name': 'foo_jni_headers',
+//          'type': 'none',
+//          'sources': [
+//            'java/src/org/chromium/example/jni_generator/SampleForTests.java',
+//          ],
+//          'variables': {
+//            'jni_gen_package': 'foo',
+//          },
+//          'includes': [ '../../../build/jni_generator.gypi' ],
+//        },
+//        {
+//          'target_name': 'foo_java',
+//          'type': 'none',
+//          'dependencies': [
+//            '../../../base/base.gyp:base',
+//          ],
+//          'variables': {
+//            'java_in_dir': 'java',
+//          },
+//          'includes': [ '../../../build/java.gypi' ],
+//        },
+//      ],
+//    }],
+//  ],
+//
+// - GN Build must be configured to generate bindings:
+//  # Add import at top of file:
+//  if (is_android) {
+//    import("//build/config/android/rules.gni")  # For generate_jni().
+//  }
+//  # ...
+//  # An example target that will rely on JNI:
+//  component("foo") {
+//    # ... normal sources, defines, deps.
+//    #     For each jni generated .java -> .h header file in jni_headers
+//    #     target there will be a single .cc file here that includes it.
+//    #
+//    # Add a dep for JNI:
+//    if (is_android) {
+//      deps += [ ":foo_jni" ]
+//    }
+//  }
+//  # ...
+//  # Create target for JNI:
+//  if (is_android) {
+//    generate_jni("jni_headers") {
+//      sources = [
+//        "java/src/org/chromium/example/jni_generator/SampleForTests.java",
+//      ]
+//      jni_package = "foo"
+//    }
+//    android_library("java") {
+//      java_files = [
+//        "java/src/org/chromium/example/jni_generator/SampleForTests.java",
+//        "java/src/org/chromium/example/jni_generator/NonJniFile.java",
+//      ]
+//    }
+//  }
+//
+// For C++ methods to be exposed to Java:
+// - The generated RegisterNativesImpl method must be called, this is typically
+//   done by having a static RegisterJNI method in the C++ class.
+// - The RegisterJNI method is added to a module's collection of register
+//   methods, such as: example_jni_registrar.h/cc files which call
+//   base::android::RegisterNativeMethods.
+//   An example_jni_registstrar.cc:
+//
+//     namespace {
+//     const base::android::RegistrationMethod kRegisteredMethods[] = {
+//         // Initial string is for debugging only.
+//         { "ExampleName", base::ExampleNameAndroid::RegisterJNI },
+//         { "ExampleName2", base::ExampleName2Android::RegisterJNI },
+//     };
+//     }  // namespace
+//
+//     bool RegisterModuleNameJni(JNIEnv* env) {
+//       return RegisterNativeMethods(env, kRegisteredMethods,
+//                                    arraysize(kRegisteredMethods));
+//     }
+//
+//  - Each module's RegisterModuleNameJni must be called by a larger module,
+//    or application during startup.
+//
 class CPPClass {
  public:
   CPPClass();
   ~CPPClass();
 
+  // Register C++ methods exposed to Java using JNI.
+  static bool RegisterJNI(JNIEnv* env);
+
+  // Java @CalledByNative methods implicitly available to C++ via the _jni.h
+  // file included in the .cc file.
+
   class InnerClass {
    public:
-    jdouble MethodOtherP0(JNIEnv* env, jobject obj);
+    jdouble MethodOtherP0(JNIEnv* env,
+                          const base::android::JavaParamRef<jobject>& caller);
   };
 
-  void Destroy(JNIEnv* env, jobject obj);
+  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& caller);
 
-  jint Method(JNIEnv* env, jobject obj);
+  jint Method(JNIEnv* env, const base::android::JavaParamRef<jobject>& caller);
 
-  void AddStructB(JNIEnv* env, jobject obj, jobject structb);
+  void AddStructB(JNIEnv* env,
+                  const base::android::JavaParamRef<jobject>& caller,
+                  const base::android::JavaParamRef<jobject>& structb);
 
-  void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj);
+  void IterateAndDoSomethingWithStructB(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& caller);
 
   base::android::ScopedJavaLocalRef<jstring> ReturnAString(
-      JNIEnv* env, jobject obj);
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& caller);
 
  private:
   std::map<long, std::string> map_;
diff --git a/base/android/jni_generator/testCalledByNatives.golden b/base/android/jni_generator/testCalledByNatives.golden
index e33356a..3bc586c 100644
--- a/base/android/jni_generator/testCalledByNatives.golden
+++ b/base/android/jni_generator/testCalledByNatives.golden
@@ -32,9 +32,8 @@
 // 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,
+static ScopedJavaLocalRef<jobject> Java_TestJni_showConfirmInfoBar(JNIEnv* env,
+    jobject obj, JniIntWrapper nativeInfoBar,
     jstring buttonOk,
     jstring buttonCancel,
     jstring title,
@@ -63,13 +62,12 @@
           method_id, as_jint(nativeInfoBar), buttonOk, buttonCancel, title,
               icon);
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return 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,
+static ScopedJavaLocalRef<jobject> Java_TestJni_showAutoLoginInfoBar(JNIEnv*
+    env, jobject obj, JniIntWrapper nativeInfoBar,
     jstring realm,
     jstring account,
     jstring args) {
@@ -95,7 +93,7 @@
       env->CallObjectMethod(obj,
           method_id, as_jint(nativeInfoBar), realm, account, args);
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_InfoBar_dismiss = 0;
@@ -151,8 +149,8 @@
 }
 
 static base::subtle::AtomicWord g_TestJni_openUrl = 0;
-static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv*
-    env, jstring url) {
+static ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv* env, jstring
+    url) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, TestJni_clazz(env),
       TestJni_clazz(env), NULL);
@@ -172,7 +170,7 @@
       env->CallStaticObjectMethod(TestJni_clazz(env),
           method_id, url);
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_activateHardwareAcceleration = 0;
@@ -232,8 +230,8 @@
 }
 
 static base::subtle::AtomicWord g_TestJni_returnByteArray = 0;
-static base::android::ScopedJavaLocalRef<jbyteArray>
-    Java_TestJni_returnByteArray(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jbyteArray> Java_TestJni_returnByteArray(JNIEnv* env,
+    jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -252,12 +250,12 @@
       static_cast<jbyteArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jbyteArray>(env, ret);
+  return ScopedJavaLocalRef<jbyteArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnBooleanArray = 0;
-static base::android::ScopedJavaLocalRef<jbooleanArray>
-    Java_TestJni_returnBooleanArray(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jbooleanArray> Java_TestJni_returnBooleanArray(JNIEnv*
+    env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -276,12 +274,12 @@
       static_cast<jbooleanArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jbooleanArray>(env, ret);
+  return ScopedJavaLocalRef<jbooleanArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnCharArray = 0;
-static base::android::ScopedJavaLocalRef<jcharArray>
-    Java_TestJni_returnCharArray(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jcharArray> Java_TestJni_returnCharArray(JNIEnv* env,
+    jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -300,12 +298,12 @@
       static_cast<jcharArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jcharArray>(env, ret);
+  return ScopedJavaLocalRef<jcharArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnShortArray = 0;
-static base::android::ScopedJavaLocalRef<jshortArray>
-    Java_TestJni_returnShortArray(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jshortArray> Java_TestJni_returnShortArray(JNIEnv*
+    env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -324,12 +322,12 @@
       static_cast<jshortArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jshortArray>(env, ret);
+  return ScopedJavaLocalRef<jshortArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnIntArray = 0;
-static base::android::ScopedJavaLocalRef<jintArray>
-    Java_TestJni_returnIntArray(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jintArray> Java_TestJni_returnIntArray(JNIEnv* env,
+    jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -348,12 +346,12 @@
       static_cast<jintArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jintArray>(env, ret);
+  return ScopedJavaLocalRef<jintArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnLongArray = 0;
-static base::android::ScopedJavaLocalRef<jlongArray>
-    Java_TestJni_returnLongArray(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jlongArray> Java_TestJni_returnLongArray(JNIEnv* env,
+    jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -372,12 +370,12 @@
       static_cast<jlongArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jlongArray>(env, ret);
+  return ScopedJavaLocalRef<jlongArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnDoubleArray = 0;
-static base::android::ScopedJavaLocalRef<jdoubleArray>
-    Java_TestJni_returnDoubleArray(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jdoubleArray> Java_TestJni_returnDoubleArray(JNIEnv*
+    env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -396,12 +394,12 @@
       static_cast<jdoubleArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jdoubleArray>(env, ret);
+  return ScopedJavaLocalRef<jdoubleArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnObjectArray = 0;
-static base::android::ScopedJavaLocalRef<jobjectArray>
-    Java_TestJni_returnObjectArray(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jobjectArray> Java_TestJni_returnObjectArray(JNIEnv*
+    env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -420,11 +418,11 @@
       static_cast<jobjectArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
+  return ScopedJavaLocalRef<jobjectArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnArrayOfByteArray = 0;
-static base::android::ScopedJavaLocalRef<jobjectArray>
+static ScopedJavaLocalRef<jobjectArray>
     Java_TestJni_returnArrayOfByteArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
@@ -444,12 +442,12 @@
       static_cast<jobjectArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
+  return ScopedJavaLocalRef<jobjectArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_getCompressFormat = 0;
-static base::android::ScopedJavaLocalRef<jobject>
-    Java_TestJni_getCompressFormat(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jobject> Java_TestJni_getCompressFormat(JNIEnv* env,
+    jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -468,12 +466,12 @@
       env->CallObjectMethod(obj,
           method_id);
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_getCompressFormatList = 0;
-static base::android::ScopedJavaLocalRef<jobject>
-    Java_TestJni_getCompressFormatList(JNIEnv* env, jobject obj) {
+static ScopedJavaLocalRef<jobject> Java_TestJni_getCompressFormatList(JNIEnv*
+    env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -492,7 +490,7 @@
       env->CallObjectMethod(obj,
           method_id);
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testConstantsFromJavaP.golden b/base/android/jni_generator/testConstantsFromJavaP.golden
index 1c816bc..97c00f9 100644
--- a/base/android/jni_generator/testConstantsFromJavaP.golden
+++ b/base/android/jni_generator/testConstantsFromJavaP.golden
@@ -135,7 +135,7 @@
 
 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>
+static 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,
@@ -151,7 +151,7 @@
     JniIntWrapper p11,
     JniIntWrapper p12,
     JniIntWrapper p13) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
+static 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,
@@ -184,12 +184,12 @@
               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);
+  return 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>
+static ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
     jlong p0,
     jlong p1,
@@ -204,7 +204,7 @@
     JniIntWrapper p10,
     JniIntWrapper p11,
     JniIntWrapper p12) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
+static ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
     jlong p0,
     jlong p1,
@@ -235,12 +235,12 @@
           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);
+  return 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>
+static 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,
@@ -253,7 +253,7 @@
     jfloat p9,
     JniIntWrapper p10,
     JniIntWrapper p11) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
+static 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,
@@ -282,12 +282,12 @@
           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);
+  return 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>
+static 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,
@@ -301,7 +301,7 @@
     jfloat p10,
     JniIntWrapper p11,
     JniIntWrapper p12) __attribute__ ((unused));
-static base::android::ScopedJavaLocalRef<jobject>
+static 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,
@@ -331,18 +331,18 @@
           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);
+  return ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_I = 0;
-static base::android::ScopedJavaLocalRef<jobject>
+static 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>
+static ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
     jlong p1,
     JniIntWrapper p2,
@@ -364,15 +364,14 @@
       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);
+  return 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) {
+static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainAVME_AVME(JNIEnv* env,
+    jobject p0) __attribute__ ((unused));
+static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainAVME_AVME(JNIEnv* env,
+    jobject p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, MotionEvent_clazz(env),
       MotionEvent_clazz(env), NULL);
@@ -388,15 +387,14 @@
       env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0);
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return 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) {
+static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainNoHistory(JNIEnv* env,
+    jobject p0) __attribute__ ((unused));
+static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainNoHistory(JNIEnv* env,
+    jobject p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, MotionEvent_clazz(env),
       MotionEvent_clazz(env), NULL);
@@ -412,7 +410,7 @@
       env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0);
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_recycle = 0;
@@ -2103,11 +2101,10 @@
 }
 
 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) {
+static ScopedJavaLocalRef<jstring> Java_MotionEvent_toString(JNIEnv* env,
+    jobject obj) __attribute__ ((unused));
+static ScopedJavaLocalRef<jstring> Java_MotionEvent_toString(JNIEnv* env,
+    jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
       MotionEvent_clazz(env), NULL);
@@ -2123,15 +2120,14 @@
       static_cast<jstring>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+  return 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) {
+static ScopedJavaLocalRef<jstring> Java_MotionEvent_actionToString(JNIEnv* env,
+    JniIntWrapper p0) __attribute__ ((unused));
+static ScopedJavaLocalRef<jstring> Java_MotionEvent_actionToString(JNIEnv* env,
+    JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, MotionEvent_clazz(env),
       MotionEvent_clazz(env), NULL);
@@ -2147,15 +2143,14 @@
       static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, as_jint(p0)));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+  return 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) {
+static ScopedJavaLocalRef<jstring> Java_MotionEvent_axisToString(JNIEnv* env,
+    JniIntWrapper p0) __attribute__ ((unused));
+static ScopedJavaLocalRef<jstring> Java_MotionEvent_axisToString(JNIEnv* env,
+    JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, MotionEvent_clazz(env),
       MotionEvent_clazz(env), NULL);
@@ -2171,7 +2166,7 @@
       static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, as_jint(p0)));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+  return ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_axisFromString = 0;
diff --git a/base/android/jni_generator/testEagerCalledByNativesOption.golden b/base/android/jni_generator/testEagerCalledByNativesOption.golden
index 19108bf..b01cd39 100644
--- a/base/android/jni_generator/testEagerCalledByNativesOption.golden
+++ b/base/android/jni_generator/testEagerCalledByNativesOption.golden
@@ -29,12 +29,14 @@
 }  // namespace
 
 // Step 2: method stubs.
-static jint Method(JNIEnv* env, jobject jcaller,
+static jint Java_org_chromium_example_jni_1generator_Test_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);
+  return native->Method(env, JavaParamRef<jobject>(env, jcaller), arg1);
 }
 
 namespace {
@@ -58,12 +60,11 @@
   return ret;
 }
 
-static base::android::ScopedJavaLocalRef<jstring>
-    testStaticMethodWithNoParam(JNIEnv* env) {
+static 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);
+  return ScopedJavaLocalRef<jstring>(env, ret);
 }
 }  // namespace
 
@@ -75,7 +76,9 @@
 "J"
 "I"
 ")"
-"I", reinterpret_cast<void*>(Method) },
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_Test_nativeMethod)
+    },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
diff --git a/base/android/jni_generator/testFromJavaP.golden b/base/android/jni_generator/testFromJavaP.golden
index b7276bc..f32666c 100644
--- a/base/android/jni_generator/testFromJavaP.golden
+++ b/base/android/jni_generator/testFromJavaP.golden
@@ -230,10 +230,9 @@
 }
 
 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) {
+static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env)
+    __attribute__ ((unused));
+static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, InputStream_clazz(env),
       InputStream_clazz(env), NULL);
@@ -249,7 +248,7 @@
       env->NewObject(InputStream_clazz(env),
           method_id);
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden
index 5a525ef..ad140e2 100644
--- a/base/android/jni_generator/testInnerClassNatives.golden
+++ b/base/android/jni_generator/testInnerClassNatives.golden
@@ -26,17 +26,24 @@
 
 }  // namespace
 
-static jint Init(JNIEnv* env, jobject jcaller);
-
 // Step 2: method stubs.
 
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+static jint Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env,
+    jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
+}
+
 // Step 3: RegisterNatives.
 
 static const JNINativeMethod kMethodsMyInnerClass[] = {
     { "nativeInit",
 "("
 ")"
-"I", reinterpret_cast<void*>(Init) },
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_00024MyInnerClass_nativeInit)
+    },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
index c8d4b3c..0a890e7 100644
--- a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
+++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
@@ -27,26 +27,37 @@
 
 }  // namespace
 
-static jint Init(JNIEnv* env, jobject jcaller);
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
 // Step 2: method stubs.
 
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+static jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env, jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
+}
+
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+static jint Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
+}
+
 // Step 3: RegisterNatives.
 
 static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
     { "nativeInit",
 "("
 ")"
-"I", reinterpret_cast<void*>(Init) },
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit)
+    },
 };
 
 static const JNINativeMethod kMethodsTestJni[] = {
     { "nativeInit",
 "("
 ")"
-"I", reinterpret_cast<void*>(Init) },
+"I", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeInit) },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden
index 42643ae..268f794 100644
--- a/base/android/jni_generator/testInnerClassNativesMultiple.golden
+++ b/base/android/jni_generator/testInnerClassNativesMultiple.golden
@@ -28,26 +28,40 @@
 
 }  // namespace
 
-static jint Init(JNIEnv* env, jobject jcaller);
-
-static jint Init(JNIEnv* env, jobject jcaller);
-
 // Step 2: method stubs.
 
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+static jint Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env,
+    jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
+}
+
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+static jint Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
+}
+
 // Step 3: RegisterNatives.
 
 static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
     { "nativeInit",
 "("
 ")"
-"I", reinterpret_cast<void*>(Init) },
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit)
+    },
 };
 
 static const JNINativeMethod kMethodsMyInnerClass[] = {
     { "nativeInit",
 "("
 ")"
-"I", reinterpret_cast<void*>(Init) },
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_00024MyInnerClass_nativeInit)
+    },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/base/android/jni_generator/testJNIInitNativeNameOption.golden b/base/android/jni_generator/testJNIInitNativeNameOption.golden
index a0998da..46a57ac 100644
--- a/base/android/jni_generator/testJNIInitNativeNameOption.golden
+++ b/base/android/jni_generator/testJNIInitNativeNameOption.golden
@@ -26,12 +26,14 @@
 }  // namespace
 
 // Step 2: method stubs.
-static jint Method(JNIEnv* env, jobject jcaller,
+static jint Java_org_chromium_example_jni_1generator_Test_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);
+  return native->Method(env, JavaParamRef<jobject>(env, jcaller), arg1);
 }
 
 // Step 3: RegisterNatives.
@@ -42,7 +44,9 @@
 "J"
 "I"
 ")"
-"I", reinterpret_cast<void*>(Method) },
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_Test_nativeMethod)
+    },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
diff --git a/base/android/jni_generator/testJarJarRemapping.golden b/base/android/jni_generator/testJarJarRemapping.golden
index 2f85122..fe13952 100644
--- a/base/android/jni_generator/testJarJarRemapping.golden
+++ b/base/android/jni_generator/testJarJarRemapping.golden
@@ -25,20 +25,48 @@
 
 }  // 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.
 
+static void Test(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jobject>& t);
+
+static void Java_com_test_jni_1generator_Example_nativeTest(JNIEnv* env, jclass
+    jcaller,
+    jobject t) {
+  return Test(env, JavaParamRef<jclass>(env, jcaller),
+      JavaParamRef<jobject>(env, t));
+}
+
+static void Test2(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jobject>& t);
+
+static void Java_com_test_jni_1generator_Example_nativeTest2(JNIEnv* env, jclass
+    jcaller,
+    jobject t) {
+  return Test2(env, JavaParamRef<jclass>(env, jcaller),
+      JavaParamRef<jobject>(env, t));
+}
+
+static void Test3(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jobject>& t);
+
+static void Java_com_test_jni_1generator_Example_nativeTest3(JNIEnv* env, jclass
+    jcaller,
+    jobject t) {
+  return Test3(env, JavaParamRef<jclass>(env, jcaller),
+      JavaParamRef<jobject>(env, t));
+}
+
+static void Test4(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jobject>& t);
+
+static void Java_com_test_jni_1generator_Example_nativeTest4(JNIEnv* env, jclass
+    jcaller,
+    jobject t) {
+  return Test4(env, JavaParamRef<jclass>(env, jcaller),
+      JavaParamRef<jobject>(env, t));
+}
+
 // Step 3: RegisterNatives.
 
 static const JNINativeMethod kMethodsExample[] = {
@@ -46,22 +74,25 @@
 "("
 "Lorg/test2/Test;"
 ")"
-"V", reinterpret_cast<void*>(Test) },
+"V", reinterpret_cast<void*>(Java_com_test_jni_1generator_Example_nativeTest) },
     { "nativeTest2",
 "("
 "Lorg/chromium/example3/PrefixFoo;"
 ")"
-"V", reinterpret_cast<void*>(Test2) },
+"V", reinterpret_cast<void*>(Java_com_test_jni_1generator_Example_nativeTest2)
+    },
     { "nativeTest3",
 "("
 "Lorg/test3/Test;"
 ")"
-"V", reinterpret_cast<void*>(Test3) },
+"V", reinterpret_cast<void*>(Java_com_test_jni_1generator_Example_nativeTest3)
+    },
     { "nativeTest4",
 "("
 "Lorg/test3/TestBar$Inner;"
 ")"
-"V", reinterpret_cast<void*>(Test4) },
+"V", reinterpret_cast<void*>(Java_com_test_jni_1generator_Example_nativeTest4)
+    },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
index b0db9dd..6de8c21 100644
--- a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -25,12 +25,21 @@
 
 }  // namespace
 
-static void DoSomething(JNIEnv* env, jclass jcaller,
-    jobject callback1,
-    jobject callback2);
-
 // Step 2: method stubs.
 
+static void DoSomething(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jobject>& callback1,
+    const JavaParamRef<jobject>& callback2);
+
+static void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv* env, jclass
+    jcaller,
+    jobject callback1,
+    jobject callback2) {
+  return DoSomething(env, JavaParamRef<jclass>(env, jcaller),
+      JavaParamRef<jobject>(env, callback1), JavaParamRef<jobject>(env,
+      callback2));
+}
+
 static base::subtle::AtomicWord g_Foo_calledByNative = 0;
 static void Java_Foo_calledByNative(JNIEnv* env, jobject callback1,
     jobject callback2) {
@@ -64,7 +73,7 @@
 "Lorg/chromium/foo/Bar1$Callback;"
 "Lorg/chromium/foo/Bar2$Callback;"
 ")"
-"V", reinterpret_cast<void*>(DoSomething) },
+"V", reinterpret_cast<void*>(Java_org_chromium_foo_Foo_nativeDoSomething) },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/base/android/jni_generator/testNativeExportsOption.golden b/base/android/jni_generator/testNativeExportsOption.golden
index 395fc39..13cd2b9 100644
--- a/base/android/jni_generator/testNativeExportsOption.golden
+++ b/base/android/jni_generator/testNativeExportsOption.golden
@@ -26,32 +26,8 @@
 
 }  // 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")))
+extern "C" __attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
     env,
@@ -60,10 +36,10 @@
     jint arg1) {
   Test* native = reinterpret_cast<Test*>(nativeTest);
   CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
-  return native->StaticMethod(env, jcaller, arg1);
+  return native->StaticMethod(env, JavaParamRef<jobject>(env, jcaller), arg1);
 }
 
-__attribute__((visibility("default")))
+extern "C" __attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
     env,
@@ -72,7 +48,25 @@
     jint arg1) {
   Test* native = reinterpret_cast<Test*>(nativeTest);
   CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
-  return native->Method(env, jcaller, arg1);
+  return native->Method(env, JavaParamRef<jobject>(env, jcaller), arg1);
+}
+
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+extern "C" __attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
+}
+
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+extern "C" __attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
 }
 
 static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
@@ -101,7 +95,7 @@
 
 static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
     0;
-static base::android::ScopedJavaLocalRef<jstring>
+static ScopedJavaLocalRef<jstring>
     Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
     JniIntWrapper iParam) {
   /* Must call RegisterNativesImpl()  */
@@ -123,7 +117,7 @@
       static_cast<jstring>(env->CallObjectMethod(obj,
           method_id, as_jint(iParam)));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+  return ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
@@ -176,7 +170,7 @@
 
 static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
     0;
-static base::android::ScopedJavaLocalRef<jstring>
+static ScopedJavaLocalRef<jstring>
     Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, SampleForTests_clazz(env),
@@ -196,9 +190,8 @@
 static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+  return ScopedJavaLocalRef<jstring>(env, ret);
 }
-};  // extern "C"
 
 // Step 3: RegisterNatives.
 
diff --git a/base/android/jni_generator/testNativeExportsOptionalOption.golden b/base/android/jni_generator/testNativeExportsOptionalOption.golden
index f47cb98..e2cf051 100644
--- a/base/android/jni_generator/testNativeExportsOptionalOption.golden
+++ b/base/android/jni_generator/testNativeExportsOptionalOption.golden
@@ -26,32 +26,8 @@
 
 }  // 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")))
+extern "C" __attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
     env,
@@ -60,10 +36,10 @@
     jint arg1) {
   Test* native = reinterpret_cast<Test*>(nativeTest);
   CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
-  return native->StaticMethod(env, jcaller, arg1);
+  return native->StaticMethod(env, JavaParamRef<jobject>(env, jcaller), arg1);
 }
 
-__attribute__((visibility("default")))
+extern "C" __attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
     env,
@@ -72,7 +48,25 @@
     jint arg1) {
   Test* native = reinterpret_cast<Test*>(nativeTest);
   CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
-  return native->Method(env, jcaller, arg1);
+  return native->Method(env, JavaParamRef<jobject>(env, jcaller), arg1);
+}
+
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+extern "C" __attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
+}
+
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+extern "C" __attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
 }
 
 static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
@@ -101,7 +95,7 @@
 
 static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
     0;
-static base::android::ScopedJavaLocalRef<jstring>
+static ScopedJavaLocalRef<jstring>
     Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
     JniIntWrapper iParam) {
   /* Must call RegisterNativesImpl()  */
@@ -123,7 +117,7 @@
       static_cast<jstring>(env->CallObjectMethod(obj,
           method_id, as_jint(iParam)));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+  return ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
@@ -176,7 +170,7 @@
 
 static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
     0;
-static base::android::ScopedJavaLocalRef<jstring>
+static ScopedJavaLocalRef<jstring>
     Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, SampleForTests_clazz(env),
@@ -196,9 +190,8 @@
 static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
           method_id));
   jni_generator::CheckException(env);
-  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+  return ScopedJavaLocalRef<jstring>(env, ret);
 }
-};  // extern "C"
 
 // Step 3: RegisterNatives.
 
diff --git a/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden
index e5a4fab..f9538a3 100644
--- a/base/android/jni_generator/testNatives.golden
+++ b/base/android/jni_generator/testNatives.golden
@@ -25,39 +25,25 @@
 
 }  // 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,
+
+static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+
+static jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env, jobject jcaller) {
+  return Init(env, JavaParamRef<jobject>(env, jcaller));
+}
+
+static void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
+    jobject jcaller,
     jint nativeChromeBrowserProvider) {
   ChromeBrowserProvider* native =
       reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
   CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
-  return native->Destroy(env, jcaller);
+  return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
 }
 
-static jlong AddBookmark(JNIEnv* env, jobject jcaller,
+static jlong Java_org_chromium_TestJni_nativeAddBookmark(JNIEnv* env,
+    jobject jcaller,
     jint nativeChromeBrowserProvider,
     jstring url,
     jstring title,
@@ -66,10 +52,71 @@
   ChromeBrowserProvider* native =
       reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
   CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmark", 0);
-  return native->AddBookmark(env, jcaller, url, title, isFolder, parentId);
+  return native->AddBookmark(env, JavaParamRef<jobject>(env, jcaller),
+      JavaParamRef<jstring>(env, url), JavaParamRef<jstring>(env, title),
+      isFolder, parentId);
 }
 
-static jlong AddBookmarkFromAPI(JNIEnv* env, jobject jcaller,
+static ScopedJavaLocalRef<jstring> GetDomainAndRegistry(JNIEnv* env, const
+    JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jstring>& url);
+
+static jstring Java_org_chromium_TestJni_nativeGetDomainAndRegistry(JNIEnv* env,
+    jclass jcaller,
+    jstring url) {
+  return GetDomainAndRegistry(env, JavaParamRef<jclass>(env, jcaller),
+      JavaParamRef<jstring>(env, url)).Release();
+}
+
+static void CreateHistoricalTabFromState(JNIEnv* env, const
+    JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jbyteArray>& state,
+    jint tab_index);
+
+static void Java_org_chromium_TestJni_nativeCreateHistoricalTabFromState(JNIEnv*
+    env, jclass jcaller,
+    jbyteArray state,
+    jint tab_index) {
+  return CreateHistoricalTabFromState(env, JavaParamRef<jclass>(env, jcaller),
+      JavaParamRef<jbyteArray>(env, state), tab_index);
+}
+
+static ScopedJavaLocalRef<jbyteArray> GetStateAsByteArray(JNIEnv* env, const
+    JavaParamRef<jobject>& jcaller,
+    const JavaParamRef<jobject>& view);
+
+static jbyteArray Java_org_chromium_TestJni_nativeGetStateAsByteArray(JNIEnv*
+    env, jobject jcaller,
+    jobject view) {
+  return GetStateAsByteArray(env, JavaParamRef<jobject>(env, jcaller),
+      JavaParamRef<jobject>(env, view)).Release();
+}
+
+static ScopedJavaLocalRef<jobjectArray> GetAutofillProfileGUIDs(JNIEnv* env,
+    const JavaParamRef<jclass>& jcaller);
+
+static jobjectArray
+    Java_org_chromium_TestJni_nativeGetAutofillProfileGUIDs(JNIEnv* env, jclass
+    jcaller) {
+  return GetAutofillProfileGUIDs(env, JavaParamRef<jclass>(env,
+      jcaller)).Release();
+}
+
+static void SetRecognitionResults(JNIEnv* env, const JavaParamRef<jobject>&
+    jcaller,
+    jint sessionId,
+    const JavaParamRef<jobjectArray>& results);
+
+static void Java_org_chromium_TestJni_nativeSetRecognitionResults(JNIEnv* env,
+    jobject jcaller,
+    jint sessionId,
+    jobjectArray results) {
+  return SetRecognitionResults(env, JavaParamRef<jobject>(env, jcaller),
+      sessionId, JavaParamRef<jobjectArray>(env, results));
+}
+
+static jlong Java_org_chromium_TestJni_nativeAddBookmarkFromAPI(JNIEnv* env,
+    jobject jcaller,
     jint nativeChromeBrowserProvider,
     jstring url,
     jobject created,
@@ -81,11 +128,33 @@
   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);
+  return native->AddBookmarkFromAPI(env, JavaParamRef<jobject>(env, jcaller),
+      JavaParamRef<jstring>(env, url), JavaParamRef<jobject>(env, created),
+      JavaParamRef<jobject>(env, isBookmark), JavaParamRef<jobject>(env, date),
+      JavaParamRef<jbyteArray>(env, favicon), JavaParamRef<jstring>(env, title),
+      JavaParamRef<jobject>(env, visits));
 }
 
-static jobject QueryBitmap(JNIEnv* env, jobject jcaller,
+static jint FindAll(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
+    const JavaParamRef<jstring>& find);
+
+static jint Java_org_chromium_TestJni_nativeFindAll(JNIEnv* env, jobject
+    jcaller,
+    jstring find) {
+  return FindAll(env, JavaParamRef<jobject>(env, jcaller),
+      JavaParamRef<jstring>(env, find));
+}
+
+static ScopedJavaLocalRef<jobject> GetInnerClass(JNIEnv* env, const
+    JavaParamRef<jclass>& jcaller);
+
+static jobject Java_org_chromium_TestJni_nativeGetInnerClass(JNIEnv* env, jclass
+    jcaller) {
+  return GetInnerClass(env, JavaParamRef<jclass>(env, jcaller)).Release();
+}
+
+static jobject Java_org_chromium_TestJni_nativeQueryBitmap(JNIEnv* env,
+    jobject jcaller,
     jint nativeChromeBrowserProvider,
     jobjectArray projection,
     jstring selection,
@@ -94,11 +163,14 @@
   ChromeBrowserProvider* native =
       reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
   CHECK_NATIVE_PTR(env, jcaller, native, "QueryBitmap", NULL);
-  return native->QueryBitmap(env, jcaller, projection, selection, selectionArgs,
-      sortOrder).Release();
+  return native->QueryBitmap(env, JavaParamRef<jobject>(env, jcaller),
+      JavaParamRef<jobjectArray>(env, projection), JavaParamRef<jstring>(env,
+      selection), JavaParamRef<jobjectArray>(env, selectionArgs),
+      JavaParamRef<jstring>(env, sortOrder)).Release();
 }
 
-static void GotOrientation(JNIEnv* env, jobject jcaller,
+static void Java_org_chromium_TestJni_nativeGotOrientation(JNIEnv* env,
+    jobject jcaller,
     jint nativeDataFetcherImplAndroid,
     jdouble alpha,
     jdouble beta,
@@ -106,7 +178,19 @@
   DataFetcherImplAndroid* native =
       reinterpret_cast<DataFetcherImplAndroid*>(nativeDataFetcherImplAndroid);
   CHECK_NATIVE_PTR(env, jcaller, native, "GotOrientation");
-  return native->GotOrientation(env, jcaller, alpha, beta, gamma);
+  return native->GotOrientation(env, JavaParamRef<jobject>(env, jcaller), alpha,
+      beta, gamma);
+}
+
+static ScopedJavaLocalRef<jthrowable> MessWithJavaException(JNIEnv* env, const
+    JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jthrowable>& e);
+
+static jthrowable Java_org_chromium_TestJni_nativeMessWithJavaException(JNIEnv*
+    env, jclass jcaller,
+    jthrowable e) {
+  return MessWithJavaException(env, JavaParamRef<jclass>(env, jcaller),
+      JavaParamRef<jthrowable>(env, e)).Release();
 }
 
 // Step 3: RegisterNatives.
@@ -115,12 +199,12 @@
     { "nativeInit",
 "("
 ")"
-"I", reinterpret_cast<void*>(Init) },
+"I", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeInit) },
     { "nativeDestroy",
 "("
 "I"
 ")"
-"V", reinterpret_cast<void*>(Destroy) },
+"V", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeDestroy) },
     { "nativeAddBookmark",
 "("
 "I"
@@ -129,33 +213,43 @@
 "Z"
 "J"
 ")"
-"J", reinterpret_cast<void*>(AddBookmark) },
+"J", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeAddBookmark) },
     { "nativeGetDomainAndRegistry",
 "("
 "Ljava/lang/String;"
 ")"
-"Ljava/lang/String;", reinterpret_cast<void*>(GetDomainAndRegistry) },
+"Ljava/lang/String;",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeGetDomainAndRegistry)
+    },
     { "nativeCreateHistoricalTabFromState",
 "("
 "[B"
 "I"
 ")"
-"V", reinterpret_cast<void*>(CreateHistoricalTabFromState) },
+"V",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeCreateHistoricalTabFromState)
+    },
     { "nativeGetStateAsByteArray",
 "("
 "Landroid/view/View;"
 ")"
-"[B", reinterpret_cast<void*>(GetStateAsByteArray) },
+"[B",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeGetStateAsByteArray)
+    },
     { "nativeGetAutofillProfileGUIDs",
 "("
 ")"
-"[Ljava/lang/String;", reinterpret_cast<void*>(GetAutofillProfileGUIDs) },
+"[Ljava/lang/String;",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeGetAutofillProfileGUIDs)
+    },
     { "nativeSetRecognitionResults",
 "("
 "I"
 "[Ljava/lang/String;"
 ")"
-"V", reinterpret_cast<void*>(SetRecognitionResults) },
+"V",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeSetRecognitionResults)
+    },
     { "nativeAddBookmarkFromAPI",
 "("
 "I"
@@ -167,17 +261,18 @@
 "Ljava/lang/String;"
 "Ljava/lang/Integer;"
 ")"
-"J", reinterpret_cast<void*>(AddBookmarkFromAPI) },
+"J", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeAddBookmarkFromAPI)
+    },
     { "nativeFindAll",
 "("
 "Ljava/lang/String;"
 ")"
-"I", reinterpret_cast<void*>(FindAll) },
+"I", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeFindAll) },
     { "nativeGetInnerClass",
 "("
 ")"
 "Lorg/chromium/example/jni_generator/SampleForTests$OnFrameAvailableListener;",
-    reinterpret_cast<void*>(GetInnerClass) },
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeGetInnerClass) },
     { "nativeQueryBitmap",
 "("
 "I"
@@ -186,7 +281,8 @@
 "[Ljava/lang/String;"
 "Ljava/lang/String;"
 ")"
-"Landroid/graphics/Bitmap;", reinterpret_cast<void*>(QueryBitmap) },
+"Landroid/graphics/Bitmap;",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeQueryBitmap) },
     { "nativeGotOrientation",
 "("
 "I"
@@ -194,7 +290,14 @@
 "D"
 "D"
 ")"
-"V", reinterpret_cast<void*>(GotOrientation) },
+"V", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeGotOrientation) },
+    { "nativeMessWithJavaException",
+"("
+"Ljava/lang/Throwable;"
+")"
+"Ljava/lang/Throwable;",
+    reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeMessWithJavaException)
+    },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden
index 5fa901c..d5b67ba 100644
--- a/base/android/jni_generator/testNativesLong.golden
+++ b/base/android/jni_generator/testNativesLong.golden
@@ -26,12 +26,13 @@
 }  // namespace
 
 // Step 2: method stubs.
-static void Destroy(JNIEnv* env, jobject jcaller,
+static void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
+    jobject jcaller,
     jlong nativeChromeBrowserProvider) {
   ChromeBrowserProvider* native =
       reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
   CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
-  return native->Destroy(env, jcaller);
+  return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
 }
 
 // Step 3: RegisterNatives.
@@ -41,7 +42,7 @@
 "("
 "J"
 ")"
-"V", reinterpret_cast<void*>(Destroy) },
+"V", reinterpret_cast<void*>(Java_org_chromium_TestJni_nativeDestroy) },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/base/android/jni_generator/testPureNativeMethodsOption.golden b/base/android/jni_generator/testPureNativeMethodsOption.golden
index ad63cca..52e03cc 100644
--- a/base/android/jni_generator/testPureNativeMethodsOption.golden
+++ b/base/android/jni_generator/testPureNativeMethodsOption.golden
@@ -26,7 +26,9 @@
 }  // namespace
 
 // Step 2: method stubs.
-static jlong Method(JNIEnv* env, jobject jcaller,
+static jlong Java_org_chromium_example_jni_1generator_Test_nativeMethod(JNIEnv*
+    env,
+    jobject jcaller,
     jlong nativeTest,
     jint arg1) {
   Test* native = reinterpret_cast<Test*>(nativeTest);
@@ -42,7 +44,9 @@
 "J"
 "I"
 ")"
-"J", reinterpret_cast<void*>(Method) },
+"J",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_Test_nativeMethod)
+    },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
index 1cf6554..1b2895e 100644
--- a/base/android/jni_generator/testSingleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -25,11 +25,18 @@
 
 }  // namespace
 
-static void DoSomething(JNIEnv* env, jclass jcaller,
-    jobject callback);
-
 // Step 2: method stubs.
 
+static void DoSomething(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
+    const JavaParamRef<jobject>& callback);
+
+static void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv* env, jclass
+    jcaller,
+    jobject callback) {
+  return DoSomething(env, JavaParamRef<jclass>(env, jcaller),
+      JavaParamRef<jobject>(env, callback));
+}
+
 static base::subtle::AtomicWord g_Foo_calledByNative = 0;
 static void Java_Foo_calledByNative(JNIEnv* env, jobject callback) {
   /* Must call RegisterNativesImpl()  */
@@ -60,7 +67,7 @@
 "("
 "Lorg/chromium/foo/Bar$Callback;"
 ")"
-"V", reinterpret_cast<void*>(DoSomething) },
+"V", reinterpret_cast<void*>(Java_org_chromium_foo_Foo_nativeDoSomething) },
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/base/android/jni_string.cc b/base/android/jni_string.cc
index 57c2805..0bc3659 100644
--- a/base/android/jni_string.cc
+++ b/base/android/jni_string.cc
@@ -29,12 +29,18 @@
     result->clear();
     return;
   }
+  const jsize length = env->GetStringLength(str);
+  if (!length) {
+    result->clear();
+    CheckException(env);
+    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);
+  UTF16ToUTF8(chars, length, result);
   env->ReleaseStringChars(str, chars);
   CheckException(env);
 }
@@ -49,6 +55,10 @@
   return ConvertJavaStringToUTF8(AttachCurrentThread(), str.obj());
 }
 
+std::string ConvertJavaStringToUTF8(JNIEnv* env, const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF8(env, str.obj());
+}
+
 ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
     JNIEnv* env,
     const base::StringPiece& str) {
@@ -69,11 +79,17 @@
     result->clear();
     return;
   }
+  const jsize length = env->GetStringLength(str);
+  if (!length) {
+    result->clear();
+    CheckException(env);
+    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));
+  result->assign(chars, length);
   env->ReleaseStringChars(str, chars);
   CheckException(env);
 }
@@ -88,6 +104,10 @@
   return ConvertJavaStringToUTF16(AttachCurrentThread(), str.obj());
 }
 
+string16 ConvertJavaStringToUTF16(JNIEnv* env, const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF16(env, str.obj());
+}
+
 ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
     JNIEnv* env,
     const base::StringPiece16& str) {
diff --git a/base/android/jni_string.h b/base/android/jni_string.h
index 89af5b0..09e85f3 100644
--- a/base/android/jni_string.h
+++ b/base/android/jni_string.h
@@ -21,6 +21,8 @@
                                          std::string* result);
 BASE_EXPORT std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str);
 BASE_EXPORT std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(JNIEnv* env,
+                                                const JavaRef<jstring>& str);
 
 // Convert a std string to Java string.
 BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
@@ -33,6 +35,8 @@
                                           string16* result);
 BASE_EXPORT string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str);
 BASE_EXPORT string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(JNIEnv* env,
+                                              const JavaRef<jstring>& str);
 
 // Convert a string16 to a Java string.
 BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
diff --git a/base/android/jni_string_unittest.cc b/base/android/jni_string_unittest.cc
index abd0683..3da8b87 100644
--- a/base/android/jni_string_unittest.cc
+++ b/base/android/jni_string_unittest.cc
@@ -28,5 +28,21 @@
   EXPECT_EQ(kSimpleString, result);
 }
 
+TEST(JniString, EmptyConversionUTF8) {
+  const std::string kEmptyString = "";
+  JNIEnv* env = AttachCurrentThread();
+  std::string result =
+      ConvertJavaStringToUTF8(ConvertUTF8ToJavaString(env, kEmptyString));
+  EXPECT_EQ(kEmptyString, result);
+}
+
+TEST(JniString, EmptyConversionUTF16) {
+  const string16 kEmptyString = UTF8ToUTF16("");
+  JNIEnv* env = AttachCurrentThread();
+  string16 result =
+      ConvertJavaStringToUTF16(ConvertUTF16ToJavaString(env, kEmptyString));
+  EXPECT_EQ(kEmptyString, result);
+}
+
 }  // namespace android
 }  // namespace base
diff --git a/base/android/jni_weak_ref.cc b/base/android/jni_weak_ref.cc
index 35a76da..55244f2 100644
--- a/base/android/jni_weak_ref.cc
+++ b/base/android/jni_weak_ref.cc
@@ -47,11 +47,8 @@
 base::android::ScopedJavaLocalRef<jobject> GetRealObject(
     JNIEnv* env, jweak obj) {
   jobject real = NULL;
-  if (obj) {
+  if (obj)
     real = env->NewLocalRef(obj);
-    if (!real)
-      DLOG(ERROR) << "The real object has been deleted!";
-  }
   return base::android::ScopedJavaLocalRef<jobject>(env, real);
 }
 
diff --git a/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java b/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
index d3441f7..bfcd7aa 100644
--- a/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
+++ b/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
@@ -13,6 +13,7 @@
 import junit.framework.Assert;
 
 import org.chromium.base.BaseChromiumApplication.WindowFocusChangedListener;
+import org.chromium.base.test.shadows.ShadowMultiDex;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -25,10 +26,12 @@
 
 /** Unit tests for {@link BaseChromiumApplication}. */
 @RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
-        shadows = {BaseChromiumApplicationTest.TrackingShadowActivity.class})
+@Config(manifest = Config.NONE,
+        application = BaseChromiumApplication.class,
+        shadows = {BaseChromiumApplicationTest.TrackingShadowActivity.class, ShadowMultiDex.class})
 public class BaseChromiumApplicationTest {
 
+    /** Shadow that tracks calls to onWindowFocusChanged and dispatchKeyEvent. */
     @Implements(Activity.class)
     public static class TrackingShadowActivity extends ShadowActivity {
         private int mWindowFocusCalls;
@@ -65,30 +68,4 @@
         // Also ensure that the original activity is forwarded the notification.
         Assert.assertEquals(1, shadow.mWindowFocusCalls);
     }
-
-    @Test
-    public void testDispatchKeyEvent() throws Exception {
-        ActivityController<Activity> controller =
-                Robolectric.buildActivity(Activity.class).create().start().visible();
-        TrackingShadowActivity shadow =
-                (TrackingShadowActivity) Robolectric.shadowOf(controller.get());
-
-        final KeyEvent menuKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
-
-        // Ensure that key events are forwarded.
-        Assert.assertFalse(controller.get().getWindow().getCallback().dispatchKeyEvent(menuKey));
-        // This gets called twice - once to see if the activity is swallowing it, and again to
-        // dispatch it.
-        Assert.assertEquals(2, shadow.mDispatchKeyEventCalls);
-
-        // Ensure that our activity can swallow the event.
-        shadow.mReturnValueForKeyDispatch = true;
-        Assert.assertTrue(controller.get().getWindow().getCallback().dispatchKeyEvent(menuKey));
-        Assert.assertEquals(3, shadow.mDispatchKeyEventCalls);
-
-        // A non-enter key only dispatches once.
-        Assert.assertTrue(controller.get().getWindow().getCallback().dispatchKeyEvent(
-                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
-        Assert.assertEquals(4, shadow.mDispatchKeyEventCalls);
-    }
 }
diff --git a/base/android/junit/src/org/chromium/base/LogTest.java b/base/android/junit/src/org/chromium/base/LogTest.java
index 46bdc67..745ac8c 100644
--- a/base/android/junit/src/org/chromium/base/LogTest.java
+++ b/base/android/junit/src/org/chromium/base/LogTest.java
@@ -12,30 +12,14 @@
 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})
+@Config(manifest = Config.NONE)
 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() {
@@ -48,6 +32,14 @@
                 logs.get(0).msg.matches("\\[LogTest.java:\\d+\\].*"));
     }
 
+    @Test
+    public void normalizeTagTest() {
+        assertEquals("cr_foo", Log.normalizeTag("cr.foo"));
+        assertEquals("cr_foo", Log.normalizeTag("cr_foo"));
+        assertEquals("cr_foo", Log.normalizeTag("foo"));
+        assertEquals("cr_ab_foo", Log.normalizeTag("ab_foo"));
+    }
+
     /** Tests that exceptions provided to the log functions are properly recognized and printed. */
     @Test
     public void exceptionLoggingTest() {
@@ -87,13 +79,4 @@
         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
index 9591d3f..8910d48 100644
--- a/base/android/library_loader/library_load_from_apk_status_codes.h
+++ b/base/android/library_loader/library_load_from_apk_status_codes.h
@@ -17,11 +17,13 @@
   // 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 does not support loading a library directly from the APK file
+  // (obsolete).
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_NOT_SUPPORTED_OBSOLETE = 1,
 
   // The device supports loading a library directly from the APK file.
-  LIBRARY_LOAD_FROM_APK_STATUS_CODES_SUPPORTED = 2,
+  // (obsolete).
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_SUPPORTED_OBSOLETE = 2,
 
   // The Chromium library was successfully loaded directly from the APK file.
   LIBRARY_LOAD_FROM_APK_STATUS_CODES_SUCCESSFUL = 3,
@@ -31,8 +33,9 @@
   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,
+  // support fallback (obsolete).
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_USED_NO_MAP_EXEC_SUPPORT_FALLBACK_OBSOLETE
+      = 5,
 
   // End sentinel.
   LIBRARY_LOAD_FROM_APK_STATUS_CODES_MAX = 6,
diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc
index 0b59a30..67b7c5d 100644
--- a/base/android/library_loader/library_loader_hooks.cc
+++ b/base/android/library_loader/library_loader_hooks.cc
@@ -48,13 +48,19 @@
 
 RendererHistogramCode g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
 
+// The amount of time, in milliseconds, that it took to load the shared
+// libraries in the renderer. Set in
+// RegisterChromiumAndroidLinkerRendererHistogram.
+long g_renderer_library_load_time_ms = 0;
+
 } // namespace
 
 static void RegisterChromiumAndroidLinkerRendererHistogram(
     JNIEnv* env,
-    jobject jcaller,
+    const JavaParamRef<jobject>& jcaller,
     jboolean requested_shared_relro,
-    jboolean load_at_fixed_address_failed) {
+    jboolean load_at_fixed_address_failed,
+    jlong library_load_time_ms) {
   // Note a pending histogram value for later recording.
   if (requested_shared_relro) {
     g_renderer_histogram_code = load_at_fixed_address_failed
@@ -62,6 +68,8 @@
   } else {
     g_renderer_histogram_code = LFA_NOT_ATTEMPTED;
   }
+
+  g_renderer_library_load_time_ms = library_load_time_ms;
 }
 
 void RecordChromiumAndroidLinkerRendererHistogram() {
@@ -72,14 +80,19 @@
                             g_renderer_histogram_code,
                             MAX_RENDERER_HISTOGRAM_CODE);
   g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
+
+  // Record how long it took to load the shared libraries.
+  UMA_HISTOGRAM_TIMES("ChromiumAndroidLinker.RendererLoadTime",
+      base::TimeDelta::FromMilliseconds(g_renderer_library_load_time_ms));
 }
 
 static void RecordChromiumAndroidLinkerBrowserHistogram(
     JNIEnv* env,
-    jobject jcaller,
+    const JavaParamRef<jobject>& jcaller,
     jboolean is_using_browser_shared_relros,
     jboolean load_at_fixed_address_failed,
-    jint library_load_from_apk_status) {
+    jint library_load_from_apk_status,
+    jlong library_load_time_ms) {
   // 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;
@@ -97,19 +110,25 @@
   UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.LibraryLoadFromApkStatus",
                             library_load_from_apk_status,
                             LIBRARY_LOAD_FROM_APK_STATUS_CODES_MAX);
+
+  // Record how long it took to load the shared libraries.
+  UMA_HISTOGRAM_TIMES("ChromiumAndroidLinker.BrowserLoadTime",
+                      base::TimeDelta::FromMilliseconds(library_load_time_ms));
 }
 
 void SetLibraryLoadedHook(LibraryLoadedHook* func) {
   g_registration_callback = func;
 }
 
-static void InitCommandLine(JNIEnv* env,
-                            jobject jcaller,
-                            jobjectArray init_command_line) {
+static void InitCommandLine(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jcaller,
+    const JavaParamRef<jobjectArray>& init_command_line) {
   InitNativeCommandLineFromJavaArray(env, init_command_line);
 }
 
-static jboolean LibraryLoaded(JNIEnv* env, jobject jcaller) {
+static jboolean LibraryLoaded(JNIEnv* env,
+                              const JavaParamRef<jobject>& jcaller) {
   if (g_registration_callback == NULL) {
     return true;
   }
@@ -123,7 +142,9 @@
   }
 }
 
-static jboolean ForkAndPrefetchNativeLibrary(JNIEnv* env, jclass clazz) {
+static jboolean ForkAndPrefetchNativeLibrary(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz) {
   return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
 }
 
@@ -135,8 +156,10 @@
   g_library_version_number = strdup(version_number);
 }
 
-jstring GetVersionNumber(JNIEnv* env, jobject jcaller) {
-  return ConvertUTF8ToJavaString(env, g_library_version_number).Release();
+ScopedJavaLocalRef<jstring> GetVersionNumber(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jcaller) {
+  return ConvertUTF8ToJavaString(env, g_library_version_number);
 }
 
 LibraryProcessType GetLibraryProcessType(JNIEnv* env) {
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
index 798a283..118e80c 100644
--- a/base/android/library_loader/library_prefetcher.cc
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -36,7 +36,7 @@
 
 bool PathMatchesSuffix(const std::string& path) {
   for (size_t i = 0; i < arraysize(kSuffixesToMatch); i++) {
-    if (EndsWith(path, kSuffixesToMatch[i], true)) {
+    if (EndsWith(path, kSuffixesToMatch[i], CompareCase::SENSITIVE)) {
       return true;
     }
   }
@@ -82,14 +82,14 @@
     std::vector<AddressRange>* ranges) {
   bool has_libchrome_region = false;
   for (const base::debug::MappedMemoryRegion& region : regions) {
-    if (EndsWith(region.path, kLibchromeSuffix, true)) {
+    if (EndsWith(region.path, kLibchromeSuffix, CompareCase::SENSITIVE)) {
       has_libchrome_region = true;
       break;
     }
   }
   for (const base::debug::MappedMemoryRegion& region : regions) {
     if (has_libchrome_region &&
-        !EndsWith(region.path, kLibchromeSuffix, true)) {
+        !EndsWith(region.path, kLibchromeSuffix, CompareCase::SENSITIVE)) {
       continue;
     }
     ranges->push_back(std::make_pair(region.start, region.end));
@@ -118,6 +118,12 @@
 
 // static
 bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
+  // Avoid forking with cygprofile instrumentation because the latter performs
+  // memory allocations.
+#if defined(CYGPROFILE_INSTRUMENTATION)
+  return false;
+#endif
+
   // 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
@@ -126,6 +132,7 @@
   std::vector<AddressRange> ranges;
   if (!FindRanges(&ranges))
     return false;
+
   pid_t pid = fork();
   if (pid == 0) {
     setpriority(PRIO_PROCESS, 0, kBackgroundPriority);
diff --git a/base/android/linker/BUILD.gn b/base/android/linker/BUILD.gn
index 190ea47..3724b88 100644
--- a/base/android/linker/BUILD.gn
+++ b/base/android/linker/BUILD.gn
@@ -9,19 +9,20 @@
 # GYP: //base/base.gyp:chromium_android_linker
 shared_library("chromium_android_linker") {
   sources = [
+    "android_dlext.h",
+    "legacy_linker_jni.cc",
+    "legacy_linker_jni.h",
     "linker_jni.cc",
+    "linker_jni.h",
+    "modern_linker_jni.cc",
+    "modern_linker_jni.h",
   ]
 
   # 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 = [
+    "//build/config/sanitizers:deps",
     "//third_party/android_crazy_linker",
   ]
-
-  # TODO(GYP):
-  # The crazy linker is never instrumented.
-  #'cflags!': [
-  #'-finstrument-functions',
-  #],
 }
diff --git a/base/android/linker/android_dlext.h b/base/android/linker/android_dlext.h
new file mode 100644
index 0000000..edf5180
--- /dev/null
+++ b/base/android/linker/android_dlext.h
@@ -0,0 +1,77 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Definitions for android_dlopen_ext().
+//
+// This function was added for Android L-MR1 and made available in android-21
+// but we currently build Chromium with android-16. Placing the declarations
+// we need here allows code that uses android_dlopen_ext() to build with
+// android-16. At runtime we check the target's SDK_INT to ensure that we
+// are on a system new enough to offer this function, and also only access
+// it with dlsym so that the runtime linker on pre-Android L-MR1 targets will
+// not complain about a missing symbol when loading our library.
+//
+// Details below taken from:
+//   third_party/android_tools/ndk/platforms/android-21
+//       /arch-arm/usr/include/android/dlext.h
+//
+// Although taken specifically from arch-arm, there are no architecture-
+// specific elements in dlext.h. All android-21/arch-* directories contain
+// identical copies of dlext.h.
+
+#ifndef BASE_ANDROID_LINKER_ANDROID_DLEXT_H_
+#define BASE_ANDROID_LINKER_ANDROID_DLEXT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* bitfield definitions for android_dlextinfo.flags */
+enum {
+  /* When set, the reserved_addr and reserved_size fields must point to an
+   * already-reserved region of address space which will be used to load the
+   * library if it fits. If the reserved region is not large enough, the load
+   * will fail.
+   */
+  ANDROID_DLEXT_RESERVED_ADDRESS      = 0x1,
+
+  /* As DLEXT_RESERVED_ADDRESS, but if the reserved region is not large enough,
+   * the linker will choose an available address instead.
+   */
+  ANDROID_DLEXT_RESERVED_ADDRESS_HINT = 0x2,
+
+  /* When set, write the GNU RELRO section of the mapped library to relro_fd
+   * after relocation has been performed, to allow it to be reused by another
+   * process loading the same library at the same address. This implies
+   * ANDROID_DLEXT_USE_RELRO.
+   */
+  ANDROID_DLEXT_WRITE_RELRO           = 0x4,
+
+  /* When set, compare the GNU RELRO section of the mapped library to relro_fd
+   * after relocation has been performed, and replace any relocated pages that
+   * are identical with a version mapped from the file.
+   */
+  ANDROID_DLEXT_USE_RELRO             = 0x8,
+
+  /* Instruct dlopen to use library_fd instead of opening file by name.
+   * The filename parameter is still used to identify the library.
+   */
+  ANDROID_DLEXT_USE_LIBRARY_FD        = 0x10,
+
+  /* Mask of valid bits */
+  ANDROID_DLEXT_VALID_FLAG_BITS       = ANDROID_DLEXT_RESERVED_ADDRESS |
+                                        ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
+                                        ANDROID_DLEXT_WRITE_RELRO |
+                                        ANDROID_DLEXT_USE_RELRO |
+                                        ANDROID_DLEXT_USE_LIBRARY_FD,
+};
+
+typedef struct {
+  uint64_t flags;
+  void*   reserved_addr;
+  size_t  reserved_size;
+  int     relro_fd;
+  int     library_fd;
+} android_dlextinfo;
+
+#endif  // BASE_ANDROID_LINKER_ANDROID_DLEXT_H_
diff --git a/base/android/linker/config.gni b/base/android/linker/config.gni
index 99cbcf0..a84aca6 100644
--- a/base/android/linker/config.gni
+++ b/base/android/linker/config.gni
@@ -2,7 +2,8 @@
 # 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
+import("//build/config/android/config.gni")
+
+# Chromium linker crashes on component builds on Android 4.4. See b/11379966
+# Chromium linker causes instrumentation to return incorrect results.
+chromium_linker_supported = !is_component_build && !use_order_profiling
diff --git a/base/android/linker/legacy_linker_jni.cc b/base/android/linker/legacy_linker_jni.cc
new file mode 100644
index 0000000..49570ff
--- /dev/null
+++ b/base/android/linker/legacy_linker_jni.cc
@@ -0,0 +1,480 @@
+// Copyright 2014 The Chromium Authors. 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 version of the Android-specific Chromium linker that uses
+// the crazy linker to load libraries.
+
+// 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 "legacy_linker_jni.h"
+
+#include <crazy_linker.h>
+#include <fcntl.h>
+#include <jni.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "linker_jni.h"
+
+namespace chromium_android_linker {
+namespace {
+
+// 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("Set SDK build version to %d", 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.
+crazy_context_t* GetCrazyContext() {
+  static crazy_context_t* s_crazy_context = nullptr;
+
+  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_(nullptr) {}
+
+  ~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_ = nullptr;
+    return ret;
+  }
+
+ private:
+  crazy_library_t* lib_;
+};
+
+template <class LibraryOpener>
+bool GenericLoadLibrary(JNIEnv* env,
+                        const char* library_name,
+                        jlong load_address,
+                        jobject lib_info_obj,
+                        const LibraryOpener& opener) {
+  LOG_INFO("Called for %s, at address 0x%llx", library_name, load_address);
+  crazy_context_t* context = GetCrazyContext();
+
+  if (!IsValidAddress(load_address)) {
+    LOG_ERROR("Invalid address 0x%llx", 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("Could not get library information for %s: %s",
+              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("Success loading library %s", 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("Could not open %s: %s",
+              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("Could not open %s in zip file %s: %s",
+               library_name, zip_file_, crazy_context_get_error(context));
+     return false;
+  }
+  return true;
+}
+
+// Load a library with the chromium linker. This will also call its
+// JNI_OnLoad() method, which shall register its methods. Note that
+// lazy native method resolution will _not_ work after this, because
+// Dalvik uses the system's dlsym() which won't see the new library,
+// so explicit registration is mandatory.
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |library_name| is the library name (e.g. libfoo.so).
+// |load_address| is an explicit load address.
+// |library_info| is a LibInfo handle used to communicate information
+// with the Java side.
+// Return true on success.
+jboolean LoadLibrary(JNIEnv* env,
+                     jclass clazz,
+                     jstring library_name,
+                     jlong load_address,
+                     jobject lib_info_obj) {
+  String lib_name(env, library_name);
+  FileLibraryOpener opener;
+
+  return GenericLoadLibrary(env,
+                            lib_name.c_str(),
+                            static_cast<size_t>(load_address),
+                            lib_info_obj,
+                            opener);
+}
+
+// Load a library from a zipfile with the chromium linker. The
+// library in the zipfile must be uncompressed and page aligned.
+// The basename of the library is given. The library is expected
+// to be lib/<abi_tag>/crazy.<basename>. The <abi_tag> used will be the
+// same as the abi for this linker. The "crazy." prefix is included
+// so that the Android Package Manager doesn't extract the library into
+// /data/app-lib.
+//
+// Loading the library will also call its JNI_OnLoad() method, which
+// shall register its methods. Note that lazy native method resolution
+// will _not_ work after this, because Dalvik uses the system's dlsym()
+// which won't see the new library, so explicit registration is mandatory.
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |zipfile_name| is the filename of the zipfile containing the library.
+// |library_name| is the library base name (e.g. libfoo.so).
+// |load_address| is an explicit load address.
+// |library_info| is a LibInfo handle used to communicate information
+// with the Java side.
+// Returns true on success.
+jboolean LoadLibraryInZipFile(JNIEnv* env,
+                              jclass clazz,
+                              jstring zipfile_name,
+                              jstring library_name,
+                              jlong load_address,
+                              jobject lib_info_obj) {
+  String zipfile_name_str(env, zipfile_name);
+  String lib_name(env, library_name);
+  ZipLibraryOpener opener(zipfile_name_str.c_str());
+
+  return GenericLoadLibrary(env,
+                            lib_name.c_str(),
+                            static_cast<size_t>(load_address),
+                            lib_info_obj,
+                            opener);
+}
+
+// Class holding the Java class and method ID for the Java side Linker
+// postCallbackOnMainThread method.
+struct JavaCallbackBindings_class {
+  jclass clazz;
+  jmethodID method_id;
+
+  // Initialize an instance.
+  bool Init(JNIEnv* env, jclass linker_class) {
+    clazz = reinterpret_cast<jclass>(env->NewGlobalRef(linker_class));
+    return InitStaticMethodId(env,
+                              linker_class,
+                              "postCallbackOnMainThread",
+                              "(J)V",
+                              &method_id);
+  }
+};
+
+static JavaCallbackBindings_class s_java_callback_bindings;
+
+// Designated receiver function for callbacks from Java. Its name is known
+// to the Java side.
+// |env| is the current JNI environment handle and is ignored here.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |arg| is a pointer to an allocated crazy_callback_t, deleted after use.
+void RunCallbackOnUiThread(JNIEnv* env, jclass clazz, jlong arg) {
+  crazy_callback_t* callback = reinterpret_cast<crazy_callback_t*>(arg);
+
+  LOG_INFO("Called back from java with handler %p, opaque %p",
+           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("Calling back to java with handler %p, opaque %p",
+           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("Called for %s", lib_name.c_str());
+
+  if (!IsValidAddress(load_address)) {
+    LOG_ERROR("Invalid address 0x%llx", load_address);
+    return false;
+  }
+
+  ScopedLibrary library;
+  if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
+    LOG_ERROR("Could not find %s", 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("Could not create shared RELRO sharing for %s: %s\n",
+              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("Called for %s, lib_info_ref=%p", lib_name.c_str(), lib_info_obj);
+
+  ScopedLibrary library;
+  if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
+    LOG_ERROR("Could not find %s", 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("library=%s relro start=%p size=%p fd=%d",
+           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("Could not use shared RELRO for %s: %s",
+              lib_name.c_str(), crazy_context_get_error(context));
+    return false;
+  }
+
+  LOG_INFO("Library %s using shared RELRO section!", lib_name.c_str());
+
+  return true;
+}
+
+const JNINativeMethod kNativeMethods[] = {
+    {"nativeLoadLibrary",
+     "("
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&LoadLibrary)},
+    {"nativeLoadLibraryInZipFile",
+     "("
+     "Ljava/lang/String;"
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&LoadLibraryInZipFile)},
+    {"nativeRunCallbackOnUiThread",
+     "("
+     "J"
+     ")"
+     "V",
+     reinterpret_cast<void*>(&RunCallbackOnUiThread)},
+    {"nativeCreateSharedRelro",
+     "("
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&CreateSharedRelro)},
+    {"nativeUseSharedRelro",
+     "("
+     "Ljava/lang/String;"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&UseSharedRelro)},
+};
+
+}  // namespace
+
+bool LegacyLinkerJNIInit(JavaVM* vm, JNIEnv* env) {
+  LOG_INFO("Entering");
+
+  // Initialize SDK version info.
+  LOG_INFO("Retrieving SDK version info");
+  if (!InitSDKVersionInfo(env))
+    return false;
+
+  // Register native methods.
+  jclass linker_class;
+  if (!InitClassReference(env,
+                          "org/chromium/base/library_loader/LegacyLinker",
+                          &linker_class))
+    return false;
+
+  LOG_INFO("Registering native methods");
+  env->RegisterNatives(linker_class,
+                       kNativeMethods,
+                       sizeof(kNativeMethods) / sizeof(kNativeMethods[0]));
+
+  // Resolve and save the Java side Linker callback class and method.
+  LOG_INFO("Resolving callback bindings");
+  if (!s_java_callback_bindings.Init(env, linker_class)) {
+    return false;
+  }
+
+  // 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, nullptr);
+
+  return true;
+}
+
+}  // namespace chromium_android_linker
diff --git a/base/android/linker/legacy_linker_jni.h b/base/android/linker/legacy_linker_jni.h
new file mode 100644
index 0000000..fcacf12
--- /dev/null
+++ b/base/android/linker/legacy_linker_jni.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_ANDROID_LINKER_LEGACY_LINKER_JNI_H_
+#define BASE_ANDROID_LINKER_LEGACY_LINKER_JNI_H_
+
+#include <jni.h>
+
+namespace chromium_android_linker {
+
+// JNI_OnLoad() initialization hook for the legacy linker.
+// Sets up JNI and other initializations for native linker code.
+// |vm| is the Java VM handle passed to JNI_OnLoad().
+// |env| is the current JNI environment handle.
+// On success, returns true.
+extern bool LegacyLinkerJNIInit(JavaVM* vm, JNIEnv* env);
+
+}  // namespace chromium_android_linker
+
+#endif  // BASE_ANDROID_LINKER_LEGACY_LINKER_JNI_H_
diff --git a/base/android/linker/linker_jni.cc b/base/android/linker/linker_jni.cc
index b79eaf4..7b0dc81 100644
--- a/base/android/linker/linker_jni.cc
+++ b/base/android/linker/linker_jni.cc
@@ -1,83 +1,57 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. 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).
+// real Chromium libraries.
 
 // 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.
+// section of libchrome.so (or equivalent) between renderer processes.
 
 // 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 "linker_jni.h"
+
 #include <sys/mman.h>
-#include <unistd.h>
+#include <jni.h>
+#include <stdlib.h>
+#include <string.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
+#include "legacy_linker_jni.h"
+#include "modern_linker_jni.h"
 
-#define TAG "chromium_android_linker"
+namespace 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__)
+// Variable containing LibInfo for the loaded library.
+LibInfo_class s_lib_info_fields;
 
-#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_;
-};
-
+// Simple scoped UTF String class constructor.
 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);
+  // Note: This runs before browser native code is loaded, and so cannot
+  // rely on anything from base/. This means that we must use
+  // GetStringUTFChars() and not base::android::ConvertJavaStringToUTF8().
+  //
+  // GetStringUTFChars() suffices because the only strings used here are
+  // paths to APK files or names of shared libraries, all of which are
+  // plain ASCII, defined and hard-coded by the Chromium Android build.
+  //
+  // For more: see
+  //   https://crbug.com/508876
+  //
+  // Note: GetStringUTFChars() returns Java UTF-8 bytes. This is good
+  // enough for the linker though.
+  const char* bytes = env->GetStringUTFChars(str, nullptr);
   ::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|.
@@ -104,8 +78,7 @@
     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);
+  LOG_INFO("Found ID %p for field '%s'", *field_id, field_name);
   return true;
 }
 
@@ -123,8 +96,7 @@
     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);
+  LOG_INFO("Found ID %p for static method '%s'", *method_id, method_name);
   return true;
 }
 
@@ -142,9 +114,7 @@
     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);
+  LOG_INFO("Found ID %p for static field '%s'", *field_id, field_name);
   return true;
 }
 
@@ -165,653 +135,85 @@
     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);
+  LOG_INFO("Found value %d for class '%s', static field '%s'",
+           *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;
+// Use Android ASLR to create a random address into which we expect to be
+// able to load libraries. Note that this is probabilistic; we unmap the
+// address we get from mmap and assume we can re-map into it later. This
+// works the majority of the time. If it doesn't, client code backs out and
+// then loads the library normally at any available address.
+// |env| is the current JNI environment handle, and |clazz| a class.
+// Returns the address selected by ASLR, or 0 on error.
+jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz) {
+  size_t bytes = kAddressSpaceReservationSize;
 
-  // 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();
-}
+#if RESERVE_BREAKPAD_GUARD_REGION
+  // Pad the requested address space size for a Breakpad guard region.
+  bytes += kBreakpadGuardRegionBytes;
+#endif
 
-jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz, jlong bytes) {
   void* address =
-      mmap(NULL, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      mmap(nullptr, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   if (address == MAP_FAILED) {
-    LOG_INFO("%s: Random base load address not determinable\n", __FUNCTION__);
+    LOG_INFO("Random base load address not determinable");
     return 0;
   }
   munmap(address, bytes);
-  LOG_INFO("%s: Random base load address is %p\n", __FUNCTION__, address);
+
+#if RESERVE_BREAKPAD_GUARD_REGION
+  // Allow for a Breakpad guard region ahead of the returned address.
+  address = reinterpret_cast<void*>(
+      reinterpret_cast<uintptr_t>(address) + kBreakpadGuardRegionBytes);
+#endif
+
+  LOG_INFO("Random base load address is %p", 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;
-}
+namespace {
 
 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() initialization hook.
+bool LinkerJNIInit(JavaVM* vm, JNIEnv* env) {
+  LOG_INFO("Entering");
+
+  // Register native methods.
+  jclass linker_class;
+  if (!InitClassReference(env,
+                          "org/chromium/base/library_loader/Linker",
+                          &linker_class))
+    return false;
+
+  LOG_INFO("Registering native methods");
+  env->RegisterNatives(linker_class,
+                       kNativeMethods,
+                       sizeof(kNativeMethods) / sizeof(kNativeMethods[0]));
+
+  // Find LibInfo field ids.
+  LOG_INFO("Caching field IDs");
+  if (!s_lib_info_fields.Init(env)) {
+    return false;
+  }
+
+  return true;
+}
 
 // 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__);
+  LOG_INFO("Entering");
   // Get new JNIEnv
   JNIEnv* env;
   if (JNI_OK != vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) {
@@ -819,43 +221,19 @@
     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)) {
+  // Initialize linker base and implementations.
+  if (!LinkerJNIInit(vm, env)
+      || !LegacyLinkerJNIInit(vm, env) || !ModernLinkerJNIInit(vm, 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__);
+  LOG_INFO("Done");
   return JNI_VERSION_1_4;
 }
+
+}  // namespace
+}  // namespace chromium_android_linker
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+  return chromium_android_linker::JNI_OnLoad(vm, reserved);
+}
diff --git a/base/android/linker/linker_jni.h b/base/android/linker/linker_jni.h
new file mode 100644
index 0000000..b570145
--- /dev/null
+++ b/base/android/linker/linker_jni.h
@@ -0,0 +1,206 @@
+// Copyright 2015 The Chromium Authors. 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.
+
+// 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.
+
+#ifndef BASE_ANDROID_LINKER_LINKER_JNI_H_
+#define BASE_ANDROID_LINKER_LINKER_JNI_H_
+
+#include <android/log.h>
+#include <jni.h>
+#include <stdlib.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 "cr_ChromiumAndroidLinker"
+
+#if DEBUG
+#define LOG_INFO(FORMAT, ...) \
+    __android_log_print(ANDROID_LOG_INFO, TAG, \
+                        "%s: " FORMAT, __FUNCTION__, ##__VA_ARGS__)
+#else
+#define LOG_INFO(FORMAT, ...) ((void)0)
+#endif
+#define LOG_ERROR(FORMAT, ...) \
+    __android_log_print(ANDROID_LOG_ERROR, TAG, \
+                        "%s: " FORMAT, __FUNCTION__, ##__VA_ARGS__)
+
+#define UNUSED __attribute__((unused))
+
+// See commentary in crazy_linker_elf_loader.cpp for the effect of setting
+// this. If changing there, change here also.
+//
+// For more, see:
+//   https://crbug.com/504410
+#define RESERVE_BREAKPAD_GUARD_REGION 1
+
+namespace chromium_android_linker {
+
+// Larger than the largest library we might attempt to load.
+static const size_t kAddressSpaceReservationSize = 192 * 1024 * 1024;
+
+// Size of any Breakpad guard region. 16MB is comfortably larger than the
+// ~6MB relocation packing of the current 64-bit libchrome.so, the largest we
+// expect to encounter.
+#if RESERVE_BREAKPAD_GUARD_REGION
+static const size_t kBreakpadGuardRegionBytes = 16 * 1024 * 1024;
+#endif
+
+// A simple 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);
+
+  inline ~String() { ::free(ptr_); }
+
+  inline const char* c_str() const { return ptr_ ? ptr_ : ""; }
+  inline size_t size() const { return size_; }
+
+ private:
+  char* ptr_;
+  size_t size_;
+};
+
+// Return true iff |address| is a valid address for the target CPU.
+inline 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|.
+extern bool InitClassReference(JNIEnv* env,
+                               const char* class_name,
+                               jclass* clazz);
+
+// 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|.
+extern bool InitFieldId(JNIEnv* env,
+                        jclass clazz,
+                        const char* field_name,
+                        const char* field_sig,
+                        jfieldID* field_id);
+
+// 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|.
+extern bool InitStaticMethodId(JNIEnv* env,
+                               jclass clazz,
+                               const char* method_name,
+                               const char* method_sig,
+                               jmethodID* method_id);
+
+// 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|.
+extern bool InitStaticFieldId(JNIEnv* env,
+                              jclass clazz,
+                              const char* field_name,
+                              const char* field_sig,
+                              jfieldID* field_id);
+
+// 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|.
+extern bool InitStaticInt(JNIEnv* env,
+                          const char* class_name,
+                          const char* field_name,
+                          jint* value);
+
+// Use Android ASLR to create a random library load address.
+// |env| is the current JNI environment handle, and |clazz| a class.
+// Returns the address selected by ASLR.
+extern jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz);
+
+// 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);
+  }
+
+  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);
+  }
+
+  // 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) {
+    if (relro_start) {
+      *relro_start = static_cast<size_t>(
+          env->GetLongField(library_info_obj, relro_start_id));
+    }
+
+    if (relro_size) {
+      *relro_size = static_cast<size_t>(
+          env->GetLongField(library_info_obj, relro_size_id));
+    }
+
+    if (relro_fd) {
+      *relro_fd = env->GetIntField(library_info_obj, relro_fd_id);
+    }
+  }
+};
+
+// Variable containing LibInfo for the loaded library.
+extern LibInfo_class s_lib_info_fields;
+
+}  // namespace chromium_android_linker
+
+#endif  // BASE_ANDROID_LINKER_LINKER_JNI_H_
diff --git a/base/android/linker/modern_linker_jni.cc b/base/android/linker/modern_linker_jni.cc
new file mode 100644
index 0000000..65aaa4f
--- /dev/null
+++ b/base/android/linker/modern_linker_jni.cc
@@ -0,0 +1,612 @@
+// Copyright 2015 The Chromium Authors. 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 version of the Android-specific Chromium linker that uses
+// the Android M and later system linker to load libraries.
+
+// 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 "modern_linker_jni.h"
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <jni.h>
+#include <limits.h>
+#include <link.h>
+#include <string.h>
+
+#include "android_dlext.h"
+#include "linker_jni.h"
+
+#define PAGE_START(x) ((x) & PAGE_MASK)
+#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE - 1))
+
+namespace chromium_android_linker {
+namespace {
+
+// Record of the Java VM passed to JNI_OnLoad().
+static JavaVM* s_java_vm = nullptr;
+
+// Get the CPU ABI string for which the linker is running.
+//
+// The returned string is used to construct the path to libchrome.so when
+// loading directly from APK.
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// Returns the CPU ABI string for which the linker is running.
+jstring GetCpuAbi(JNIEnv* env, jclass clazz) {
+#if defined(__arm__) && defined(__ARM_ARCH_7A__)
+  static const char* kCurrentAbi = "armeabi-v7a";
+#elif defined(__arm__)
+  static const char* kCurrentAbi = "armeabi";
+#elif defined(__i386__)
+  static const char* kCurrentAbi = "x86";
+#elif defined(__mips__)
+  static const char* kCurrentAbi = "mips";
+#elif defined(__x86_64__)
+  static const char* kCurrentAbi = "x86_64";
+#elif defined(__aarch64__)
+  static const char* kCurrentAbi = "arm64-v8a";
+#else
+#error "Unsupported target abi"
+#endif
+  return env->NewStringUTF(kCurrentAbi);
+}
+
+// Convenience wrapper around dlsym() on the main executable. Returns
+// the address of the requested symbol, or nullptr if not found. Status
+// is available from dlerror().
+void* Dlsym(const char* symbol_name) {
+  static void* handle = nullptr;
+
+  if (!handle)
+    handle = dlopen(nullptr, RTLD_NOW);
+
+  void* result = dlsym(handle, symbol_name);
+  return result;
+}
+
+// dl_iterate_phdr() wrapper, accessed via dlsym lookup. Done this way.
+// so that this code compiles for Android versions that are too early to
+// offer it. Checks in LibraryLoader.java should ensure that we
+// never reach here at runtime on Android versions that are too old to
+// supply dl_iterate_phdr; that is, earlier than Android M. Returns
+// false if no dl_iterate_phdr() is available, otherwise true with the
+// return value from dl_iterate_phdr() in |status|.
+bool DlIteratePhdr(int (*callback)(dl_phdr_info*, size_t, void*),
+                   void* data,
+                   int* status) {
+  using DlIteratePhdrCallback = int (*)(dl_phdr_info*, size_t, void*);
+  using DlIteratePhdrFunctionPtr = int (*)(DlIteratePhdrCallback, void*);
+  static DlIteratePhdrFunctionPtr function_ptr = nullptr;
+
+  if (!function_ptr) {
+    function_ptr =
+        reinterpret_cast<DlIteratePhdrFunctionPtr>(Dlsym("dl_iterate_phdr"));
+    if (!function_ptr) {
+      LOG_ERROR("dlsym: dl_iterate_phdr: %s", dlerror());
+      return false;
+    }
+  }
+
+  *status = (*function_ptr)(callback, data);
+  return true;
+}
+
+// Convenience struct wrapper round android_dlextinfo.
+struct AndroidDlextinfo {
+  AndroidDlextinfo(int flags,
+                   void* reserved_addr, size_t reserved_size, int relro_fd) {
+    memset(&extinfo, 0, sizeof(extinfo));
+    extinfo.flags = flags;
+    extinfo.reserved_addr = reserved_addr;
+    extinfo.reserved_size = reserved_size;
+    extinfo.relro_fd = relro_fd;
+  }
+
+  android_dlextinfo extinfo;
+};
+
+// android_dlopen_ext() wrapper, accessed via dlsym lookup. Returns false
+// if no android_dlopen_ext() is available, otherwise true with the return
+// value from android_dlopen_ext() in |status|.
+bool AndroidDlopenExt(const char* filename,
+                      int flag,
+                      const AndroidDlextinfo* dlextinfo,
+                      void** status) {
+  using DlopenExtFunctionPtr = void* (*)(const char*,
+                                         int, const android_dlextinfo*);
+  static DlopenExtFunctionPtr function_ptr = nullptr;
+
+  if (!function_ptr) {
+    function_ptr =
+        reinterpret_cast<DlopenExtFunctionPtr>(Dlsym("android_dlopen_ext"));
+    if (!function_ptr) {
+      LOG_ERROR("dlsym: android_dlopen_ext: %s", dlerror());
+      return false;
+    }
+  }
+
+  const android_dlextinfo* extinfo = &dlextinfo->extinfo;
+  LOG_INFO("android_dlopen_ext:"
+           " flags=0x%llx, reserved_addr=%p, reserved_size=%d, relro_fd=%d",
+           static_cast<long long>(extinfo->flags),
+           extinfo->reserved_addr,
+           static_cast<int>(extinfo->reserved_size),
+           extinfo->relro_fd);
+
+  *status = (*function_ptr)(filename, flag, extinfo);
+  return true;
+}
+
+// Callback data for FindLoadedLibrarySize().
+struct CallbackData {
+  explicit CallbackData(void* address)
+      : load_address(address), load_size(0), min_vaddr(0) { }
+
+  const void* load_address;
+  size_t load_size;
+  size_t min_vaddr;
+};
+
+// Callback for dl_iterate_phdr(). Read phdrs to identify whether or not
+// this library's load address matches the |load_address| passed in
+// |data|. If yes, pass back load size and min vaddr via |data|. A non-zero
+// return value terminates iteration.
+int FindLoadedLibrarySize(dl_phdr_info* info, size_t size UNUSED, void* data) {
+  CallbackData* callback_data = reinterpret_cast<CallbackData*>(data);
+
+  // Use max and min vaddr to compute the library's load size.
+  ElfW(Addr) min_vaddr = ~0;
+  ElfW(Addr) max_vaddr = 0;
+
+  bool is_matching = false;
+  for (size_t i = 0; i < info->dlpi_phnum; ++i) {
+    const ElfW(Phdr)* phdr = &info->dlpi_phdr[i];
+    if (phdr->p_type != PT_LOAD)
+      continue;
+
+    // See if this segment's load address matches what we passed to
+    // android_dlopen_ext as extinfo.reserved_addr.
+    void* load_addr = reinterpret_cast<void*>(info->dlpi_addr + phdr->p_vaddr);
+    if (load_addr == callback_data->load_address)
+      is_matching = true;
+
+    if (phdr->p_vaddr < min_vaddr)
+      min_vaddr = phdr->p_vaddr;
+    if (phdr->p_vaddr + phdr->p_memsz > max_vaddr)
+      max_vaddr = phdr->p_vaddr + phdr->p_memsz;
+  }
+
+  // If this library matches what we seek, return its load size.
+  if (is_matching) {
+    callback_data->load_size = PAGE_END(max_vaddr) - PAGE_START(min_vaddr);
+    callback_data->min_vaddr = min_vaddr;
+    return true;
+  }
+
+  return false;
+}
+
+// Helper class for anonymous memory mapping.
+class ScopedAnonymousMmap {
+ public:
+  ScopedAnonymousMmap(void* addr, size_t size);
+
+  ~ScopedAnonymousMmap() { munmap(addr_, size_); }
+
+  void* GetAddr() const { return effective_addr_; }
+  void Release() { addr_ = nullptr; size_ = 0; effective_addr_ = nullptr; }
+
+ private:
+  void* addr_;
+  size_t size_;
+
+  // The effective_addr_ is the address seen by client code. It may or may
+  // not be the same as addr_, the real start of the anonymous mapping.
+  void* effective_addr_;
+};
+
+// ScopedAnonymousMmap constructor. |addr| is a requested mapping address, or
+// zero if any address will do, and |size| is the size of mapping required.
+ScopedAnonymousMmap::ScopedAnonymousMmap(void* addr, size_t size) {
+#if RESERVE_BREAKPAD_GUARD_REGION
+  // Increase size to extend the address reservation mapping so that it will
+  // also include a guard region from load_bias_ to start_addr. If loading
+  // at a fixed address, move our requested address back by the guard region
+  // size.
+  size += kBreakpadGuardRegionBytes;
+  if (addr) {
+    if (addr < reinterpret_cast<void*>(kBreakpadGuardRegionBytes)) {
+      LOG_ERROR("Fixed address %p is too low to accommodate Breakpad guard",
+                addr);
+      addr_ = MAP_FAILED;
+      size_ = 0;
+      return;
+    }
+    addr = reinterpret_cast<void*>(
+        reinterpret_cast<uintptr_t>(addr) - kBreakpadGuardRegionBytes);
+  }
+  LOG_INFO("Added %d to size, for Breakpad guard",
+           static_cast<int>(kBreakpadGuardRegionBytes));
+#endif
+
+  addr_ = mmap(addr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (addr_ != MAP_FAILED) {
+    size_ = size;
+  } else {
+    LOG_INFO("mmap failed: %s", strerror(errno));
+    size_ = 0;
+  }
+  effective_addr_ = addr_;
+
+#if RESERVE_BREAKPAD_GUARD_REGION
+  // If we increased size to accommodate a Breakpad guard region, move
+  // the effective address, if valid, upwards by the size of the guard region.
+  if (addr_ == MAP_FAILED)
+    return;
+  if (addr_ < reinterpret_cast<void*>(kBreakpadGuardRegionBytes)) {
+    LOG_ERROR("Map address %p is too low to accommodate Breakpad guard",
+              addr_);
+    effective_addr_ = MAP_FAILED;
+  } else {
+    effective_addr_ = reinterpret_cast<void*>(
+        reinterpret_cast<uintptr_t>(addr_) + kBreakpadGuardRegionBytes);
+  }
+#endif
+}
+
+// Helper for LoadLibrary(). Return the actual size of the library loaded
+// at |addr| in |load_size|, and the min vaddr in |min_vaddr|. Returns false
+// if the library appears not to be loaded.
+bool GetLibraryLoadSize(void* addr, size_t* load_size, size_t* min_vaddr) {
+  LOG_INFO("Called for %p", addr);
+
+  // Find the real load size and min vaddr for the library loaded at |addr|.
+  CallbackData callback_data(addr);
+  int status = 0;
+  if (!DlIteratePhdr(&FindLoadedLibrarySize, &callback_data, &status)) {
+    LOG_ERROR("No dl_iterate_phdr function found");
+    return false;
+  }
+  if (!status) {
+    LOG_ERROR("Failed to find library at address %p", addr);
+    return false;
+  }
+
+  *load_size = callback_data.load_size;
+  *min_vaddr = callback_data.min_vaddr;
+  return true;
+}
+
+// Helper for LoadLibrary(). We reserve an address space larger than
+// needed. After library loading we want to trim that reservation to only
+// what is needed.
+bool ResizeReservedAddressSpace(void* addr,
+                                size_t reserved_size,
+                                size_t load_size,
+                                size_t min_vaddr) {
+  LOG_INFO("Called for %p, reserved %d, loaded %d, min_vaddr %d",
+           addr, static_cast<int>(reserved_size),
+           static_cast<int>(load_size), static_cast<int>(min_vaddr));
+
+  const uintptr_t uintptr_addr = reinterpret_cast<uintptr_t>(addr);
+
+  if (reserved_size < load_size) {
+    LOG_ERROR("WARNING: library reservation was too small");
+    return true;
+  }
+
+  // Unmap the part of the reserved address space that is beyond the end of
+  // the loaded library data.
+  void* unmap = reinterpret_cast<void*>(uintptr_addr + load_size);
+  size_t length = reserved_size - load_size;
+  if (munmap(unmap, length) == -1) {
+    LOG_ERROR("Failed to unmap %d at %p", static_cast<int>(length), unmap);
+    return false;
+  }
+
+#if RESERVE_BREAKPAD_GUARD_REGION
+  if (min_vaddr > kBreakpadGuardRegionBytes) {
+    LOG_ERROR("WARNING: breakpad guard region reservation was too small");
+    return true;
+  }
+
+  // Unmap the part of the reserved address space that is ahead of where we
+  // actually need the guard region to start. Resizes the guard region to
+  // min_vaddr bytes.
+  unmap = reinterpret_cast<void*>(uintptr_addr - kBreakpadGuardRegionBytes);
+  length = kBreakpadGuardRegionBytes - min_vaddr;
+  if (munmap(unmap, length) == -1) {
+    LOG_ERROR("Failed to unmap %d at %p", static_cast<int>(length), unmap);
+    return false;
+  }
+#endif
+
+  return true;
+}
+
+// Load a library with the chromium linker, using android_dlopen_ext().
+//
+// android_dlopen_ext() understands how to directly load from a zipfile,
+// based on the format of |dlopen_ext_path|. If it contains a "!/" separator
+// then the string indicates <zip_path>!/<file_path> and indicates the
+// file_path element within the zip file at zip_path. A library in a
+// zipfile must be uncompressed and page aligned. 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.
+//
+// If |dlopen_ext_path| contains no "!/" separator then android_dlopen_ext()
+// assumes that it is a normal path to a standalone library file.
+//
+// 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.
+// |dlopen_ext_path| is the library identifier (e.g. libfoo.so).
+// |load_address| is an explicit load address.
+// |relro_path| is the path to the file into which RELRO data is held.
+// |lib_info_obj| is a LibInfo handle used to communicate information
+// with the Java side.
+// Return true on success.
+jboolean LoadLibrary(JNIEnv* env,
+                     jclass clazz,
+                     jstring dlopen_ext_path,
+                     jlong load_address,
+                     jobject lib_info_obj) {
+  String dlopen_library_path(env, dlopen_ext_path);
+  LOG_INFO("Called for %s, at address 0x%llx",
+           dlopen_library_path.c_str(), load_address);
+
+  if (!IsValidAddress(load_address)) {
+    LOG_ERROR("Invalid address 0x%llx", load_address);
+    return false;
+  }
+
+  const size_t size = kAddressSpaceReservationSize;
+  void* wanted_addr = reinterpret_cast<void*>(load_address);
+
+  // Reserve the address space into which we load the library.
+  ScopedAnonymousMmap mapping(wanted_addr, size);
+  void* addr = mapping.GetAddr();
+  if (addr == MAP_FAILED) {
+    LOG_ERROR("Failed to reserve space for load");
+    return false;
+  }
+  if (wanted_addr && addr != wanted_addr) {
+    LOG_ERROR("Failed to obtain fixed address for load");
+    return false;
+  }
+
+  // Build dlextinfo to load the library into the reserved space, using
+  // the shared RELRO if supplied and if its start address matches addr.
+  int relro_fd = -1;
+  int flags = ANDROID_DLEXT_RESERVED_ADDRESS;
+  if (wanted_addr && lib_info_obj) {
+    void* relro_start;
+    s_lib_info_fields.GetRelroInfo(env, lib_info_obj,
+                                   reinterpret_cast<size_t*>(&relro_start),
+                                   nullptr, &relro_fd);
+    if (relro_fd != -1 && relro_start == addr) {
+      flags |= ANDROID_DLEXT_USE_RELRO;
+    }
+  }
+  AndroidDlextinfo dlextinfo(flags, addr, size, relro_fd);
+
+  // Load the library into the reserved space.
+  const char* path = dlopen_library_path.c_str();
+  void* handle = nullptr;
+  if (!AndroidDlopenExt(path, RTLD_NOW, &dlextinfo, &handle)) {
+    LOG_ERROR("No android_dlopen_ext function found");
+    return false;
+  }
+  if (handle == nullptr) {
+    LOG_ERROR("android_dlopen_ext: %s", dlerror());
+    return false;
+  }
+
+  // After loading, trim the mapping to match the library's actual size.
+  size_t load_size = 0;
+  size_t min_vaddr = 0;
+  if (!GetLibraryLoadSize(addr, &load_size, &min_vaddr)) {
+    LOG_ERROR("Unable to find size for load at %p", addr);
+    return false;
+  }
+  if (!ResizeReservedAddressSpace(addr, size, load_size, min_vaddr)) {
+    LOG_ERROR("Unable to resize reserved address mapping");
+    return false;
+  }
+
+  // Locate and if found then call the loaded library's JNI_OnLoad() function.
+  using JNI_OnLoadFunctionPtr = int (*)(void* vm, void* reserved);
+  auto jni_onload =
+      reinterpret_cast<JNI_OnLoadFunctionPtr>(dlsym(handle, "JNI_OnLoad"));
+  if (jni_onload != nullptr) {
+    // Check that JNI_OnLoad returns a usable JNI version.
+    int jni_version = (*jni_onload)(s_java_vm, nullptr);
+    if (jni_version < JNI_VERSION_1_4) {
+      LOG_ERROR("JNI version is invalid: %d", jni_version);
+      return false;
+    }
+  }
+
+  // Release mapping before returning so that we do not unmap reserved space.
+  mapping.Release();
+
+  // Note the load address and load size in the supplied libinfo object.
+  const size_t cast_addr = reinterpret_cast<size_t>(addr);
+  s_lib_info_fields.SetLoadInfo(env, lib_info_obj, cast_addr, load_size);
+
+  LOG_INFO("Success loading library %s", dlopen_library_path.c_str());
+  return true;
+}
+
+// Create a shared RELRO file for a library, using android_dlopen_ext().
+//
+// Loads the library similarly to LoadLibrary() above, by reserving address
+// space and then using android_dlopen_ext() to load into the reserved
+// area. Adds flags to android_dlopen_ext() to saved the library's RELRO
+// memory into the given file path, then unload the library and returns.
+//
+// Does not call JNI_OnLoad() or otherwise execute any code from the library.
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |dlopen_ext_path| is the library identifier (e.g. libfoo.so).
+// |load_address| is an explicit load address.
+// |relro_path| is the path to the file into which RELRO data is written.
+// |lib_info_obj| is a LibInfo handle used to communicate information
+// with the Java side.
+// Return true on success.
+jboolean CreateSharedRelro(JNIEnv* env,
+                           jclass clazz,
+                           jstring dlopen_ext_path,
+                           jlong load_address,
+                           jstring relro_path,
+                           jobject lib_info_obj) {
+  String dlopen_library_path(env, dlopen_ext_path);
+  LOG_INFO("Called for %s, at address 0x%llx",
+           dlopen_library_path.c_str(), load_address);
+
+  if (!IsValidAddress(load_address) || load_address == 0) {
+    LOG_ERROR("Invalid address 0x%llx", load_address);
+    return false;
+  }
+
+  const size_t size = kAddressSpaceReservationSize;
+  void* wanted_addr = reinterpret_cast<void*>(load_address);
+
+  // Reserve the address space into which we load the library.
+  ScopedAnonymousMmap mapping(wanted_addr, size);
+  void* addr = mapping.GetAddr();
+  if (addr == MAP_FAILED) {
+    LOG_ERROR("Failed to reserve space for load");
+    return false;
+  }
+  if (addr != wanted_addr) {
+    LOG_ERROR("Failed to obtain fixed address for load");
+    return false;
+  }
+
+  // Open the shared RELRO file for write. Overwrites any prior content.
+  String shared_relro_path(env, relro_path);
+  const char* filepath = shared_relro_path.c_str();
+  unlink(filepath);
+  int relro_fd = open(filepath, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+  if (relro_fd == -1) {
+    LOG_ERROR("open: %s: %s", filepath, strerror(errno));
+    return false;
+  }
+
+  // Use android_dlopen_ext() to create the shared RELRO.
+  const int flags = ANDROID_DLEXT_RESERVED_ADDRESS
+                    | ANDROID_DLEXT_WRITE_RELRO;
+  AndroidDlextinfo dlextinfo(flags, addr, size, relro_fd);
+
+  const char* path = dlopen_library_path.c_str();
+  void* handle = nullptr;
+  if (!AndroidDlopenExt(path, RTLD_NOW, &dlextinfo, &handle)) {
+    LOG_ERROR("No android_dlopen_ext function found");
+    close(relro_fd);
+    return false;
+  }
+  if (handle == nullptr) {
+    LOG_ERROR("android_dlopen_ext: %s", dlerror());
+    close(relro_fd);
+    return false;
+  }
+
+  // Unload the library from this address. The reserved space is
+  // automatically unmapped on exit from this function.
+  dlclose(handle);
+
+  // Reopen the shared RELFO fd in read-only mode. This ensures that nothing
+  // can write to it through the RELRO fd that we return in libinfo.
+  close(relro_fd);
+  relro_fd = open(filepath, O_RDONLY);
+  if (relro_fd == -1) {
+    LOG_ERROR("open: %s: %s", filepath, strerror(errno));
+    return false;
+  }
+
+  // Delete the directory entry for the RELRO file. The fd we hold ensures
+  // that its data remains intact.
+  if (unlink(filepath) == -1) {
+    LOG_ERROR("unlink: %s: %s", filepath, strerror(errno));
+    return false;
+  }
+
+  // Note the shared RELRO fd in the supplied libinfo object. In this
+  // implementation the RELRO start is set to the library's load address,
+  // and the RELRO size is unused.
+  const size_t cast_addr = reinterpret_cast<size_t>(addr);
+  s_lib_info_fields.SetRelroInfo(env, lib_info_obj, cast_addr, 0, relro_fd);
+
+  LOG_INFO("Success creating shared RELRO %s", shared_relro_path.c_str());
+  return true;
+}
+
+const JNINativeMethod kNativeMethods[] = {
+    {"nativeGetCpuAbi",
+     "("
+     ")"
+     "Ljava/lang/String;",
+     reinterpret_cast<void*>(&GetCpuAbi)},
+    {"nativeLoadLibrary",
+     "("
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&LoadLibrary)},
+    {"nativeCreateSharedRelro",
+     "("
+     "Ljava/lang/String;"
+     "J"
+     "Ljava/lang/String;"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&CreateSharedRelro)},
+};
+
+}  // namespace
+
+bool ModernLinkerJNIInit(JavaVM* vm, JNIEnv* env) {
+  LOG_INFO("Entering");
+
+  // Register native methods.
+  jclass linker_class;
+  if (!InitClassReference(env,
+                          "org/chromium/base/library_loader/ModernLinker",
+                          &linker_class))
+    return false;
+
+  LOG_INFO("Registering native methods");
+  env->RegisterNatives(linker_class,
+                       kNativeMethods,
+                       sizeof(kNativeMethods) / sizeof(kNativeMethods[0]));
+
+  // Record the Java VM handle.
+  s_java_vm = vm;
+
+  return true;
+}
+
+}  // namespace chromium_android_linker
diff --git a/base/android/linker/modern_linker_jni.h b/base/android/linker/modern_linker_jni.h
new file mode 100644
index 0000000..74eb586
--- /dev/null
+++ b/base/android/linker/modern_linker_jni.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_ANDROID_LINKER_MODERN_LINKER_JNI_H_
+#define BASE_ANDROID_LINKER_MODERN_LINKER_JNI_H_
+
+#include <jni.h>
+
+namespace chromium_android_linker {
+
+// JNI_OnLoad() initialization hook for the modern linker.
+// Sets up JNI and other initializations for native linker code.
+// |vm| is the Java VM handle passed to JNI_OnLoad().
+// |env| is the current JNI environment handle.
+// On success, returns true.
+extern bool ModernLinkerJNIInit(JavaVM* vm, JNIEnv* env);
+
+}  // namespace chromium_android_linker
+
+#endif  // BASE_ANDROID_LINKER_MODERN_LINKER_JNI_H_
diff --git a/base/android/memory_pressure_listener_android.cc b/base/android/memory_pressure_listener_android.cc
index 80c07bc..5975b94 100644
--- a/base/android/memory_pressure_listener_android.cc
+++ b/base/android/memory_pressure_listener_android.cc
@@ -4,12 +4,14 @@
 
 #include "base/android/memory_pressure_listener_android.h"
 
+#include "base/android/context_utils.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) {
+static void OnMemoryPressure(JNIEnv* env,
+                             const JavaParamRef<jclass>& clazz,
+                             jint memory_pressure_level) {
   base::MemoryPressureListener::NotifyMemoryPressure(
       static_cast<base::MemoryPressureListener::MemoryPressureLevel>(
           memory_pressure_level));
diff --git a/base/android/path_service_android.cc b/base/android/path_service_android.cc
index 18ca70c..9972bbb 100644
--- a/base/android/path_service_android.cc
+++ b/base/android/path_service_android.cc
@@ -13,7 +13,10 @@
 namespace base {
 namespace android {
 
-void Override(JNIEnv* env, jclass clazz, jint what, jstring path) {
+void Override(JNIEnv* env,
+              const JavaParamRef<jclass>& clazz,
+              jint what,
+              const JavaParamRef<jstring>& path) {
   FilePath file_path(ConvertJavaStringToUTF8(env, path));
   PathService::Override(what, file_path);
 }
diff --git a/base/android/path_utils.cc b/base/android/path_utils.cc
index c98007c..85e29de 100644
--- a/base/android/path_utils.cc
+++ b/base/android/path_utils.cc
@@ -4,6 +4,7 @@
 
 #include "base/android/path_utils.h"
 
+#include "base/android/context_utils.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
@@ -41,6 +42,16 @@
   return true;
 }
 
+bool GetThumbnailCacheDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getThumbnailCacheDirectoryPath(env,
+                                                    GetApplicationContext());
+  FilePath thumbnail_cache_path(ConvertJavaStringToUTF8(path));
+  *result = thumbnail_cache_path;
+  return true;
+}
+
 bool GetDownloadsDirectory(FilePath* result) {
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jstring> path =
diff --git a/base/android/path_utils.h b/base/android/path_utils.h
index d3421b3..6501f1b 100644
--- a/base/android/path_utils.h
+++ b/base/android/path_utils.h
@@ -31,6 +31,10 @@
 // cache dir.
 BASE_EXPORT bool GetCacheDirectory(FilePath* result);
 
+// Retrieves the path to the thumbnail cache directory. The result is placed
+// in the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetThumbnailCacheDirectory(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);
diff --git a/base/android/path_utils_unittest.cc b/base/android/path_utils_unittest.cc
index c678ce2..dca8ca1 100644
--- a/base/android/path_utils_unittest.cc
+++ b/base/android/path_utils_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/android/path_utils.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/strings/string_util.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -13,14 +14,27 @@
 
 typedef testing::Test PathUtilsTest;
 
+namespace {
+void ExpectEither(const std::string& expected1,
+                  const std::string& expected2,
+                  const std::string& actual) {
+  EXPECT_TRUE(expected1 == actual || expected2 == actual)
+      << "Value of: " << actual << std::endl
+      << "Expected either: " << expected1 << std::endl
+      << "or: " << expected2;
+}
+}  // namespace
+
 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());
+
+  ExpectEither("/data/data/org.chromium.native_test/app_chrome",
+               "/data/user/0/org.chromium.native_test/app_chrome",
+               path.value());
 }
 
 TEST_F(PathUtilsTest, TestGetCacheDirectory) {
@@ -29,8 +43,9 @@
   // org.chromium.native_test
   FilePath path;
   GetCacheDirectory(&path);
-  EXPECT_STREQ("/data/data/org.chromium.native_test/cache",
-               path.value().c_str());
+  ExpectEither("/data/data/org.chromium.native_test/cache",
+               "/data/user/0/org.chromium.native_test/cache",
+               path.value());
 }
 
 TEST_F(PathUtilsTest, TestGetNativeLibraryDirectory) {
@@ -39,8 +54,11 @@
   // 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"))));
+  EXPECT_TRUE(
+      base::PathExists(path.Append("libbase_unittests.so")) ||
+      base::PathExists(path.Append("libbase_unittests.cr.so")) ||
+      base::PathExists(path.Append("lib_base_unittests__library.so")) ||
+      base::PathExists(path.Append("lib_base_unittests__library.cr.so")));
 }
 
 }  // namespace android
diff --git a/base/android/record_histogram.cc b/base/android/record_histogram.cc
index 9a68dec..51ca482 100644
--- a/base/android/record_histogram.cc
+++ b/base/android/record_histogram.cc
@@ -85,6 +85,30 @@
     return InsertLocked(j_histogram_key, histogram);
   }
 
+  HistogramBase* LinearCountHistogram(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 =
+        LinearHistogram::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) {
@@ -150,8 +174,8 @@
 }  // namespace
 
 void RecordBooleanHistogram(JNIEnv* env,
-                            jclass clazz,
-                            jstring j_histogram_name,
+                            const JavaParamRef<jclass>& clazz,
+                            const JavaParamRef<jstring>& j_histogram_name,
                             jint j_histogram_key,
                             jboolean j_sample) {
   bool sample = static_cast<bool>(j_sample);
@@ -161,8 +185,8 @@
 }
 
 void RecordEnumeratedHistogram(JNIEnv* env,
-                               jclass clazz,
-                               jstring j_histogram_name,
+                               const JavaParamRef<jclass>& clazz,
+                               const JavaParamRef<jstring>& j_histogram_name,
                                jint j_histogram_key,
                                jint j_sample,
                                jint j_boundary) {
@@ -174,8 +198,8 @@
 }
 
 void RecordCustomCountHistogram(JNIEnv* env,
-                                jclass clazz,
-                                jstring j_histogram_name,
+                                const JavaParamRef<jclass>& clazz,
+                                const JavaParamRef<jstring>& j_histogram_name,
                                 jint j_histogram_key,
                                 jint j_sample,
                                 jint j_min,
@@ -189,32 +213,49 @@
       ->Add(sample);
 }
 
+void RecordLinearCountHistogram(JNIEnv* env,
+                                const JavaParamRef<jclass>& clazz,
+                                const JavaParamRef<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()
+      .LinearCountHistogram(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) {
+                           const JavaParamRef<jclass>& clazz,
+                           const JavaParamRef<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) {
+void RecordCustomTimesHistogramMilliseconds(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<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) {
+void Initialize(JNIEnv* env, const JavaParamRef<jclass>&) {
   StatisticsRecorder::Initialize();
 }
 
@@ -222,10 +263,11 @@
 // 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) {
+jint GetHistogramValueCountForTesting(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<jstring>& histogram_name,
+    jint sample) {
   HistogramBase* histogram = StatisticsRecorder::FindHistogram(
       android::ConvertJavaStringToUTF8(env, histogram_name));
   if (histogram == nullptr) {
diff --git a/base/android/record_user_action.cc b/base/android/record_user_action.cc
index 6172f2e..1452341 100644
--- a/base/android/record_user_action.cc
+++ b/base/android/record_user_action.cc
@@ -11,7 +11,9 @@
 namespace base {
 namespace android {
 
-static void RecordUserAction(JNIEnv* env, jclass clazz, jstring j_action) {
+static void RecordUserAction(JNIEnv* env,
+                             const JavaParamRef<jclass>& clazz,
+                             const JavaParamRef<jstring>& j_action) {
   RecordComputedAction(ConvertJavaStringToUTF8(env, j_action));
 }
 
diff --git a/base/android/scoped_java_ref.cc b/base/android/scoped_java_ref.cc
index bb6f503..4d4ef6d 100644
--- a/base/android/scoped_java_ref.cc
+++ b/base/android/scoped_java_ref.cc
@@ -28,16 +28,15 @@
 
 ScopedJavaLocalFrame::~ScopedJavaLocalFrame() { env_->PopLocalFrame(NULL); }
 
-JavaRef<jobject>::JavaRef() : obj_(NULL) {}
-
+#if DCHECK_IS_ON()
+// This constructor is inlined when DCHECKs are disabled; don't add anything
+// else here.
 JavaRef<jobject>::JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {
   if (obj) {
     DCHECK(env && env->GetObjectRefType(obj) == JNILocalRefType);
   }
 }
-
-JavaRef<jobject>::~JavaRef() {
-}
+#endif
 
 JNIEnv* JavaRef<jobject>::SetNewLocalRef(JNIEnv* env, jobject obj) {
   if (!env) {
diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h
index 8047ee8..e5339ee 100644
--- a/base/android/scoped_java_ref.h
+++ b/base/android/scoped_java_ref.h
@@ -10,6 +10,8 @@
 
 #include "base/base_export.h"
 #include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/template_util.h"
 
 namespace base {
 namespace android {
@@ -45,14 +47,21 @@
   bool is_null() const { return obj_ == NULL; }
 
  protected:
-  // Initializes a NULL reference.
-  JavaRef();
+  // Initializes a NULL reference. Don't add anything else here; it's inlined.
+  JavaRef() : obj_(NULL) {}
 
   // Takes ownership of the |obj| reference passed; requires it to be a local
   // reference type.
+#if DCHECK_IS_ON()
+  // Implementation contains a DCHECK; implement out-of-line when DCHECK_IS_ON.
   JavaRef(JNIEnv* env, jobject obj);
+#else
+  // Don't add anything else here; it's inlined.
+  JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {}
+#endif
 
-  ~JavaRef();
+  // Don't add anything else here; it's inlined.
+  ~JavaRef() {}
 
   // The following are implementation detail convenience methods, for
   // use by the sub-classes.
@@ -86,6 +95,33 @@
   DISALLOW_COPY_AND_ASSIGN(JavaRef);
 };
 
+// Holds a local reference to a JNI method parameter.
+// Method parameters should not be deleted, and so this class exists purely to
+// wrap them as a JavaRef<T> in the JNI binding generator. Do not create
+// instances manually.
+template<typename T>
+class JavaParamRef : public JavaRef<T> {
+ public:
+  // Assumes that |obj| is a parameter passed to a JNI method from Java.
+  // Does not assume ownership as parameters should not be deleted.
+  JavaParamRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj) {}
+
+  // Allow nullptr to be converted to JavaParamRef. Some unit tests call JNI
+  // methods directly from C++ and pass null for objects which are not actually
+  // used by the implementation (e.g. the caller object); allow this to keep
+  // working.
+  JavaParamRef(std::nullptr_t) : JavaRef<T>() {}
+
+  ~JavaParamRef() {}
+
+  // TODO(torne): remove this cast once we're using JavaRef consistently.
+  // http://crbug.com/506850
+  operator T() const { return JavaRef<T>::obj(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(JavaParamRef);
+};
+
 // 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
@@ -149,12 +185,14 @@
 
   template<typename U>
   void Reset(JNIEnv* env, U obj) {
-    implicit_cast<T>(obj);  // Ensure U is assignable to T
+    static_assert(base::is_convertible<U, T>::value,
+                  "U must be convertible 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.
+  // local reference when it is done with it. Note that calling a Java method
+  // is *not* a transfer of ownership and Release() should not be used.
   T Release() {
     return static_cast<T>(this->ReleaseInternal());
   }
@@ -163,6 +201,13 @@
   // 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_;
+
+  // Prevent ScopedJavaLocalRef(JNIEnv*, T obj) from being used to take
+  // ownership of a JavaParamRef's underlying object - parameters are not
+  // allowed to be deleted and so should not be owned by ScopedJavaLocalRef.
+  // TODO(torne): this can be removed once JavaParamRef no longer has an
+  // implicit conversion back to T.
+  ScopedJavaLocalRef(JNIEnv* env, const JavaParamRef<T>& other);
 };
 
 // Holds a global reference to a Java object. The global reference is scoped
@@ -199,13 +244,20 @@
   }
 
   template<typename U>
+  void Reset(JNIEnv* env, const JavaParamRef<U>& other) {
+    this->Reset(env, other.obj());
+  }
+
+  template<typename U>
   void Reset(JNIEnv* env, U obj) {
-    implicit_cast<T>(obj);  // Ensure U is assignable to T
+    static_assert(base::is_convertible<U, T>::value,
+                  "U must be convertible 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.
+  // global reference when it is done with it. Note that calling a Java method
+  // is *not* a transfer of ownership and Release() should not be used.
   T Release() {
     return static_cast<T>(this->ReleaseInternal());
   }
diff --git a/base/android/trace_event_binding.cc b/base/android/trace_event_binding.cc
index 791b67f..f761a64 100644
--- a/base/android/trace_event_binding.cc
+++ b/base/android/trace_event_binding.cc
@@ -8,6 +8,7 @@
 
 #include <set>
 
+#include "base/android/jni_string.h"
 #include "base/lazy_instance.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_impl.h"
@@ -25,32 +26,28 @@
 // Boilerplate for safely converting Java data to TRACE_EVENT data.
 class TraceEventDataConverter {
  public:
-  TraceEventDataConverter(JNIEnv* env,
-                          jstring jname,
-                          jstring jarg)
+  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) {
-  }
+        name_(ConvertJavaStringToUTF8(env, jname)),
+        has_arg_(jarg != nullptr),
+        arg_(jarg ? ConvertJavaStringToUTF8(env, jarg) : "") {}
   ~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_; }
+  const char* name() { return name_.c_str(); }
+  const char* arg_name() { return has_arg_ ? "arg" : nullptr; }
+  const char* arg() { return has_arg_ ? arg_.c_str() : nullptr; }
 
  private:
   JNIEnv* env_;
   jstring jname_;
   jstring jarg_;
-  const char* name_;
-  const char* arg_;
+  std::string name_;
+  bool has_arg_;
+  std::string arg_;
 
   DISALLOW_COPY_AND_ASSIGN(TraceEventDataConverter);
 };
@@ -72,23 +69,26 @@
 
 }  // namespace
 
-static void RegisterEnabledObserver(JNIEnv* env, jclass clazz) {
+static void RegisterEnabledObserver(JNIEnv* env,
+                                    const JavaParamRef<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) {
+static void StartATrace(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   base::trace_event::TraceLog::GetInstance()->StartATrace();
 }
 
-static void StopATrace(JNIEnv* env, jclass clazz) {
+static void StopATrace(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   base::trace_event::TraceLog::GetInstance()->StopATrace();
 }
 
-static void Instant(JNIEnv* env, jclass clazz,
-                    jstring jname, jstring jarg) {
+static void Instant(JNIEnv* env,
+                    const JavaParamRef<jclass>& clazz,
+                    const JavaParamRef<jstring>& jname,
+                    const JavaParamRef<jstring>& jarg) {
   TraceEventDataConverter converter(env, jname, jarg);
   if (converter.arg()) {
     TRACE_EVENT_COPY_INSTANT1(kJavaCategory, converter.name(),
@@ -100,8 +100,10 @@
   }
 }
 
-static void Begin(JNIEnv* env, jclass clazz,
-                  jstring jname, jstring jarg) {
+static void Begin(JNIEnv* env,
+                  const JavaParamRef<jclass>& clazz,
+                  const JavaParamRef<jstring>& jname,
+                  const JavaParamRef<jstring>& jarg) {
   TraceEventDataConverter converter(env, jname, jarg);
   if (converter.arg()) {
     TRACE_EVENT_COPY_BEGIN1(kJavaCategory, converter.name(),
@@ -111,8 +113,10 @@
   }
 }
 
-static void End(JNIEnv* env, jclass clazz,
-                jstring jname, jstring jarg) {
+static void End(JNIEnv* env,
+                const JavaParamRef<jclass>& clazz,
+                const JavaParamRef<jstring>& jname,
+                const JavaParamRef<jstring>& jarg) {
   TraceEventDataConverter converter(env, jname, jarg);
   if (converter.arg()) {
     TRACE_EVENT_COPY_END1(kJavaCategory, converter.name(),
@@ -122,20 +126,26 @@
   }
 }
 
-static void BeginToplevel(JNIEnv* env, jclass clazz) {
+static void BeginToplevel(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   TRACE_EVENT_BEGIN0(kToplevelCategory, kLooperDispatchMessage);
 }
 
-static void EndToplevel(JNIEnv* env, jclass clazz) {
+static void EndToplevel(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   TRACE_EVENT_END0(kToplevelCategory, kLooperDispatchMessage);
 }
 
-static void StartAsync(JNIEnv* env, jclass clazz, jstring jname, jlong jid) {
+static void StartAsync(JNIEnv* env,
+                       const JavaParamRef<jclass>& clazz,
+                       const JavaParamRef<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) {
+static void FinishAsync(JNIEnv* env,
+                        const JavaParamRef<jclass>& clazz,
+                        const JavaParamRef<jstring>& jname,
+                        jlong jid) {
   TraceEventDataConverter converter(env, jname, nullptr);
   TRACE_EVENT_COPY_ASYNC_END0(kJavaCategory, converter.name(), jid);
 }
diff --git a/base/async_socket_io_handler.h b/base/async_socket_io_handler.h
deleted file mode 100644
index a22c29d..0000000
--- a/base/async_socket_io_handler.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2013 The Chromium Authors. All 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
deleted file mode 100644
index 2fffb84..0000000
--- a/base/async_socket_io_handler_posix.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2013 The Chromium Authors. All 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
deleted file mode 100644
index 721de9c..0000000
--- a/base/async_socket_io_handler_unittest.cc
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2013 The Chromium Authors. All 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
deleted file mode 100644
index e1d215c..0000000
--- a/base/async_socket_io_handler_win.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2013 The Chromium Authors. All 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/atomicops.h b/base/atomicops.h
index 6a5371c..f983b45 100644
--- a/base/atomicops.h
+++ b/base/atomicops.h
@@ -144,33 +144,6 @@
 }  // 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
@@ -188,17 +161,6 @@
 #    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
diff --git a/base/atomicops_internals_arm64_gcc.h b/base/atomicops_internals_arm64_gcc.h
deleted file mode 100644
index ddcfec9..0000000
--- a/base/atomicops_internals_arm64_gcc.h
+++ /dev/null
@@ -1,307 +0,0 @@
-// Copyright 2014 The Chromium Authors. All 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
deleted file mode 100644
index 44c91c8..0000000
--- a/base/atomicops_internals_arm_gcc.h
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright 2013 The Chromium Authors. All 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_gcc.h b/base/atomicops_internals_gcc.h
deleted file mode 100644
index 35c95fe..0000000
--- a/base/atomicops_internals_gcc.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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_mips_gcc.h b/base/atomicops_internals_mips_gcc.h
deleted file mode 100644
index b4551b8..0000000
--- a/base/atomicops_internals_mips_gcc.h
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All 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_x86_gcc.cc b/base/atomicops_internals_x86_gcc.cc
deleted file mode 100644
index c21e96d..0000000
--- a/base/atomicops_internals_x86_gcc.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// 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
deleted file mode 100644
index f0d2242..0000000
--- a/base/atomicops_internals_x86_gcc.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All 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
index 71ddca2..6ff0f44 100644
--- a/base/atomicops_internals_x86_msvc.h
+++ b/base/atomicops_internals_x86_msvc.h
@@ -109,7 +109,7 @@
 
 // 64-bit low-level operations on 64-bit platform.
 
-COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
+static_assert(sizeof(Atomic64) == sizeof(PVOID), "atomic word is atomic");
 
 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
                                          Atomic64 old_value,
diff --git a/base/atomicops_unittest.cc b/base/atomicops_unittest.cc
index 3fd5597..7298609 100644
--- a/base/atomicops_unittest.cc
+++ b/base/atomicops_unittest.cc
@@ -89,6 +89,13 @@
   EXPECT_EQ(1, value);
   EXPECT_EQ(0, prev);
 
+  // Verify that CAS will *not* change "value" if it doesn't match the
+  // expected  number. CAS will always return the actual value of the
+  // variable from before any change.
+  AtomicType fail = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 2);
+  EXPECT_EQ(1, value);
+  EXPECT_EQ(1, fail);
+
   // Use test value that has non-zero bits in both halves, more for testing
   // 64-bit implementation on 32-bit platforms.
   const AtomicType k_test_val = (static_cast<uint64_t>(1) <<
diff --git a/base/base.gyp b/base/base.gyp
index ff6ce00..6ab4b36 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -90,18 +90,6 @@
           ],
         }],
         ['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',
@@ -230,11 +218,14 @@
             }],
           ],
         }],
+        ['OS=="ios"', {
+          'sources!': [
+            'sync_socket.h',
+            'sync_socket_posix.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',
@@ -300,6 +291,8 @@
       ],
       'export_dependent_settings': [
         'base',
+        '../third_party/icu/icu.gyp:icuuc',
+        '../third_party/icu/icu.gyp:icui18n',
       ],
       'includes': [
         '../build/android/increase_size_for_speed.gypi',
@@ -442,11 +435,11 @@
         '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',
+        'base64url_unittest.cc',
         'big_endian_unittest.cc',
         'bind_unittest.cc',
         'bind_unittest.nc',
@@ -458,7 +451,6 @@
         'callback_unittest.cc',
         'callback_unittest.nc',
         'cancelable_callback_unittest.cc',
-        'chromeos/memory_pressure_monitor_unittest.cc',
         'command_line_unittest.cc',
         'containers/adapters_unittest.cc',
         'containers/hash_tables_unittest.cc',
@@ -476,6 +468,7 @@
         'debug/task_annotator_unittest.cc',
         'deferred_sequenced_task_runner_unittest.cc',
         'environment_unittest.cc',
+        'feature_list_unittest.cc',
         'file_version_info_unittest.cc',
         'files/dir_reader_posix_unittest.cc',
         'files/file_path_unittest.cc',
@@ -495,6 +488,7 @@
         'i18n/char_iterator_unittest.cc',
         'i18n/file_util_icu_unittest.cc',
         'i18n/icu_string_conversions_unittest.cc',
+        'i18n/message_formatter_unittest.cc',
         'i18n/number_formatting_unittest.cc',
         'i18n/rtl_unittest.cc',
         'i18n/streaming_utf8_validator_unittest.cc',
@@ -514,11 +508,11 @@
         'lazy_instance_unittest.cc',
         'logging_unittest.cc',
         'mac/bind_objc_block_unittest.mm',
+        'mac/call_with_eh_frame_unittest.mm',
         'mac/dispatch_source_mach_unittest.cc',
         'mac/foundation_util_unittest.mm',
         'mac/libdispatch_task_runner_unittest.cc',
         'mac/mac_util_unittest.mm',
-        'mac/memory_pressure_monitor_unittest.cc',
         'mac/objc_property_releaser_unittest.mm',
         'mac/scoped_nsobject_unittest.mm',
         'mac/scoped_objc_class_swizzler_unittest.mm',
@@ -527,17 +521,21 @@
         'memory/aligned_memory_unittest.cc',
         'memory/discardable_shared_memory_unittest.cc',
         'memory/linked_ptr_unittest.cc',
+        'memory/memory_pressure_listener_unittest.cc',
+        'memory/memory_pressure_monitor_chromeos_unittest.cc',
+        'memory/memory_pressure_monitor_mac_unittest.cc',
+        'memory/memory_pressure_monitor_win_unittest.cc',
         'memory/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/shared_memory_mac_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_task_runner_unittest.cc',
         'message_loop/message_loop_unittest.cc',
         'message_loop/message_pump_glib_unittest.cc',
         'message_loop/message_pump_io_ios_unittest.cc',
@@ -549,11 +547,12 @@
         'metrics/histogram_macros_unittest.cc',
         'metrics/histogram_snapshot_manager_unittest.cc',
         'metrics/histogram_unittest.cc',
+        'metrics/metrics_hashes_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',
+        'native_library_unittest.cc',
         'numerics/safe_numerics_unittest.cc',
         'observer_list_unittest.cc',
         'os_compat_android_unittest.cc',
@@ -591,6 +590,7 @@
         'sha1_unittest.cc',
         'stl_util_unittest.cc',
         'strings/nullable_string16_unittest.cc',
+        'strings/pattern_unittest.cc',
         'strings/safe_sprintf_unittest.cc',
         'strings/string16_unittest.cc',
         'strings/string_number_conversions_unittest.cc',
@@ -616,8 +616,6 @@
         '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',
@@ -626,6 +624,7 @@
         'threading/non_thread_safe_unittest.cc',
         'threading/platform_thread_unittest.cc',
         'threading/sequenced_worker_pool_unittest.cc',
+        'threading/sequenced_task_runner_handle_unittest.cc',
         'threading/simple_thread_unittest.cc',
         'threading/thread_checker_unittest.cc',
         'threading/thread_collision_warner_unittest.cc',
@@ -655,13 +654,13 @@
         '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_handle_unittest.cc',
         'win/scoped_process_information_unittest.cc',
         'win/scoped_variant_unittest.cc',
         'win/shortcut_unittest.cc',
@@ -699,7 +698,11 @@
         }],
         ['OS == "ios" and _toolset != "host"', {
           'sources/': [
-            # Only test the iOS-meaningful portion of process_utils.
+            # iOS does not support FilePathWatcher.
+            ['exclude', '^files/file_path_watcher_unittest\\.cc$'],
+            # Only test the iOS-meaningful portion of memory and process_utils.
+            ['exclude', '^memory/discardable_shared_memory_unittest\\.cc$'],
+            ['exclude', '^memory/shared_memory_unittest\\.cc$'],
             ['exclude', '^process/memory_unittest'],
             ['exclude', '^process/process_unittest\\.cc$'],
             ['exclude', '^process/process_util_unittest\\.cc$'],
@@ -761,6 +764,14 @@
             }],
           ]},
         ],
+        [ 'OS == "win" and target_arch == "x64"', {
+          'sources': [
+            'profiler/win32_stack_frame_unwinder_unittest.cc',
+          ],
+          'dependencies': [
+            'base_profiler_test_support_library',
+          ],
+        }],
         ['OS == "win"', {
           'sources!': [
             'file_descriptor_shuffle_unittest.cc',
@@ -819,6 +830,12 @@
         ['OS=="mac" or OS=="ios" or <(chromeos)==1 or <(chromecast)==1', {
           'defines': ['SYSTEM_NATIVE_UTF8'],
         }],
+        # SyncSocket isn't used on iOS
+        ['OS=="ios"', {
+          'sources!': [
+            'sync_socket_unittest.cc',
+          ],
+        }],
       ],  # target_conditions
     },
     {
@@ -899,16 +916,16 @@
         }],
       ],
       'sources': [
-        'test/expectations/expectation.cc',
-        'test/expectations/expectation.h',
-        'test/expectations/parser.cc',
-        'test/expectations/parser.h',
         'test/gtest_util.cc',
         'test/gtest_util.h',
+        'test/gtest_xml_unittest_result_printer.cc',
+        'test/gtest_xml_unittest_result_printer.h',
         'test/gtest_xml_util.cc',
         'test/gtest_xml_util.h',
         'test/histogram_tester.cc',
         'test/histogram_tester.h',
+        'test/icu_test_util.cc',
+        'test/icu_test_util.h',
         'test/ios/wait_util.h',
         'test/ios/wait_util.mm',
         'test/launcher/test_launcher.cc',
@@ -990,6 +1007,8 @@
         'test/test_switches.h',
         'test/test_timeouts.cc',
         'test/test_timeouts.h',
+        'test/test_ui_thread_android.cc',
+        'test/test_ui_thread_android.h',
         'test/thread_test_helper.cc',
         'test/thread_test_helper.h',
         'test/trace_event_analyzer.cc',
@@ -1041,6 +1060,22 @@
         ],
       },
     },
+    {
+      'target_name': 'test_launcher_nacl_nonsfi',
+      'conditions': [
+        ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
+          'type': 'static_library',
+          'sources': [
+            'test/launcher/test_launcher_nacl_nonsfi.cc',
+          ],
+          'dependencies': [
+            'test_support_base',
+          ],
+        }, {
+          'type': 'none',
+        }],
+      ],
+    },
   ],
   'conditions': [
     ['OS=="ios" and "<(GENERATOR)"=="ninja"', {
@@ -1164,9 +1199,6 @@
             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',
@@ -1244,6 +1276,21 @@
         },
       ],
     }],
+    ['OS == "win" and target_arch=="x64"', {
+      'targets': [
+        {
+          'target_name': 'base_profiler_test_support_library',
+          # Must be a shared library so that it can be unloaded during testing.
+          'type': 'shared_library',
+          'include_dirs': [
+            '..',
+          ],
+          'sources': [
+            'profiler/test_support_library.cc',
+          ],
+        },
+      ]
+    }],
     ['os_posix==1 and OS!="mac" and OS!="ios"', {
       'targets': [
         {
@@ -1342,11 +1389,13 @@
           'target_name': 'base_jni_headers',
           'type': 'none',
           'sources': [
+            'android/java/src/org/chromium/base/ApkAssets.java',
             'android/java/src/org/chromium/base/ApplicationStatus.java',
             'android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java',
             'android/java/src/org/chromium/base/BuildInfo.java',
             'android/java/src/org/chromium/base/CommandLine.java',
             'android/java/src/org/chromium/base/ContentUriUtils.java',
+            'android/java/src/org/chromium/base/ContextUtils.java',
             'android/java/src/org/chromium/base/CpuFeatures.java',
             'android/java/src/org/chromium/base/EventLog.java',
             'android/java/src/org/chromium/base/FieldTrialList.java',
@@ -1385,11 +1434,12 @@
           'includes': [ '../build/jar_file_jni_generator.gypi' ],
         },
         {
-          # TODO(GN)
+          # GN: //base:base_unittests_jni_headers
           'target_name': 'base_unittests_jni_headers',
           'type': 'none',
           'sources': [
             'test/android/java/src/org/chromium/base/ContentUriTestUtils.java',
+            'test/android/java/src/org/chromium/base/TestUiThread.java',
           ],
           'variables': {
             'jni_gen_package': 'base',
@@ -1410,6 +1460,22 @@
           'includes': [ '../build/android/java_cpp_template.gypi' ],
         },
         {
+          # GN: //base:base_multidex_gen
+          'target_name': 'base_multidex_gen',
+          'type': 'none',
+          'sources': [
+            'android/java/templates/ChromiumMultiDex.template',
+          ],
+          'variables': {
+            'package_name': 'org/chromium/base/multidex',
+            'template_deps': [],
+            'additional_gcc_preprocess_options': [
+              '--defines', 'MULTIDEX_CONFIGURATION_<(CONFIGURATION_NAME)',
+            ],
+          },
+          'includes': ['../build/android/java_cpp_template.gypi'],
+        },
+        {
           # GN: //base:base_android_java_enums_srcjar
           'target_name': 'base_java_library_process_type',
           'type': 'none',
@@ -1423,7 +1489,7 @@
           'target_name': 'base_java',
           'type': 'none',
           'variables': {
-            'java_in_dir': '../base/android/java',
+            'java_in_dir': 'android/java',
             'jar_excluded_classes': [ '*/NativeLibraries.class' ],
           },
           'dependencies': [
@@ -1431,7 +1497,9 @@
             'base_java_library_load_from_apk_status_codes',
             'base_java_library_process_type',
             'base_java_memory_pressure_level',
+            'base_multidex_gen',
             'base_native_libraries_gen',
+            '../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib',
             '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
           ],
           'includes': [ '../build/java.gypi' ],
@@ -1489,12 +1557,30 @@
           'includes': [ '../build/java.gypi' ],
         },
         {
+          # TODO(jbudorick): Remove this once we roll to robolectric 3.0 and pull
+          # in the multidex shadow library. crbug.com/522043
+          # GN: //base:base_junit_test_support
+          'target_name': 'base_junit_test_support',
+          'type': 'none',
+          'dependencies': [
+            '../testing/android/junit/junit_test.gyp:junit_test_support',
+            '../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib',
+          ],
+          'variables': {
+            'src_paths': [
+              '../base/test/android/junit/',
+            ],
+          },
+          'includes': [ '../build/host_jar.gypi' ]
+        },
+        {
           # GN: //base:base_junit_tests
           'target_name': 'base_junit_tests',
           'type': 'none',
           'dependencies': [
             'base_java',
             'base_java_test_support',
+            'base_junit_test_support',
             '../testing/android/junit/junit_test.gyp:junit_test_support',
           ],
           'variables': {
@@ -1523,7 +1609,13 @@
           'target_name': 'chromium_android_linker',
           'type': 'shared_library',
           'sources': [
+            'android/linker/android_dlext.h',
+            'android/linker/legacy_linker_jni.cc',
+            'android/linker/legacy_linker_jni.h',
             'android/linker/linker_jni.cc',
+            'android/linker/linker_jni.h',
+            'android/linker/modern_linker_jni.cc',
+            'android/linker/modern_linker_jni.h',
           ],
           # The crazy linker is never instrumented.
           'cflags!': [
@@ -1537,7 +1629,7 @@
           ],
         },
         {
-          # TODO(GN)
+          # GN: //base:base_perftests_apk
           'target_name': 'base_perftests_apk',
           'type': 'none',
           'dependencies': [
@@ -1558,26 +1650,36 @@
           ],
           'variables': {
             'test_suite_name': 'base_unittests',
+            'isolate_file': 'base_unittests.isolate',
           },
           'includes': [ '../build/apk_test.gypi' ],
         },
       ],
+      'conditions': [
+        ['test_isolation_mode != "noop"',
+          {
+            'targets': [
+              {
+                'target_name': 'base_unittests_apk_run',
+                'type': 'none',
+                'dependencies': [
+                  'base_unittests_apk',
+                ],
+                'includes': [
+                  '../build/isolate.gypi',
+                ],
+                'sources': [
+                  'base_unittests_apk.isolate',
+                ],
+              },
+            ]
+          }
+        ],
+      ],
     }],
     ['OS == "win"', {
       'targets': [
         {
-          'target_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',
@@ -1615,13 +1717,6 @@
           'sources': [
             'base_unittests.isolate',
           ],
-          'conditions': [
-            ['use_x11 == 1', {
-              'dependencies': [
-                '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
-              ],
-            }],
-          ],
         },
       ],
     }],
diff --git a/base/base.gypi b/base/base.gypi
index 82d810e..35bd747 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -18,10 +18,10 @@
           '../build/build_config.h',
           'allocator/allocator_extension.cc',
           'allocator/allocator_extension.h',
-          'allocator/type_profiler_control.cc',
-          'allocator/type_profiler_control.h',
           'android/animation_frame_time_histogram.cc',
           'android/animation_frame_time_histogram.h',
+          'android/apk_assets.cc',
+          'android/apk_assets.h',
           'android/application_status_listener.cc',
           'android/application_status_listener.h',
           'android/base_jni_onload.cc',
@@ -34,7 +34,10 @@
           'android/command_line_android.h',
           'android/content_uri_utils.cc',
           'android/content_uri_utils.h',
+          'android/context_utils.cc',
+          'android/context_utils.h',
           'android/cpu_features.cc',
+          'android/cxa_demangle_stub.cc',
           'android/event_log.cc',
           'android/event_log.h',
           'android/field_trial_list.cc',
@@ -88,16 +91,15 @@
           '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',
+          'base64url.cc',
+          'base64url.h',
           'base_export.h',
           'base_paths.cc',
           'base_paths.h',
@@ -128,8 +130,6 @@
           'callback_internal.h',
           'callback_list.h',
           'cancelable_callback.h',
-          'chromeos/memory_pressure_monitor.cc',
-          'chromeos/memory_pressure_monitor.h',
           'command_line.cc',
           'command_line.h',
           'compiler_specific.h',
@@ -178,6 +178,8 @@
           'deferred_sequenced_task_runner.h',
           'environment.cc',
           'environment.h',
+          'feature_list.cc',
+          'feature_list.h',
           'file_descriptor_posix.h',
           'file_version_info.h',
           'file_version_info_mac.h',
@@ -247,6 +249,8 @@
           'ios/device_util.mm',
           'ios/ios_util.h',
           'ios/ios_util.mm',
+          'ios/ns_error_util.h',
+          'ios/ns_error_util.mm',
           'ios/scoped_critical_action.h',
           'ios/scoped_critical_action.mm',
           'ios/weak_nsobject.h',
@@ -278,6 +282,9 @@
           'mac/bind_objc_block.h',
           'mac/bundle_locations.h',
           'mac/bundle_locations.mm',
+          'mac/call_with_eh_frame.cc',
+          'mac/call_with_eh_frame.h',
+          'mac/call_with_eh_frame_asm.S',
           'mac/close_nocancel.cc',
           'mac/cocoa_protocols.h',
           'mac/dispatch_source_mach.cc',
@@ -296,8 +303,6 @@
           'mac/mac_util.mm',
           'mac/mach_logging.cc',
           'mac/mach_logging.h',
-          'mac/memory_pressure_monitor.cc',
-          'mac/memory_pressure_monitor.h',
           'mac/objc_property_releaser.h',
           'mac/objc_property_releaser.mm',
           'mac/os_crash_dumps.cc',
@@ -315,8 +320,6 @@
           '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',
@@ -342,6 +345,12 @@
           'memory/memory_pressure_listener.h',
           'memory/memory_pressure_monitor.cc',
           'memory/memory_pressure_monitor.h',
+          'memory/memory_pressure_monitor_chromeos.cc',
+          'memory/memory_pressure_monitor_chromeos.h',
+          'memory/memory_pressure_monitor_mac.cc',
+          'memory/memory_pressure_monitor_mac.h',
+          'memory/memory_pressure_monitor_win.cc',
+          'memory/memory_pressure_monitor_win.h',
           'memory/raw_scoped_refptr_mismatch_checker.h',
           'memory/ref_counted.cc',
           'memory/ref_counted.h',
@@ -353,6 +362,10 @@
           'memory/scoped_vector.h',
           'memory/shared_memory.h',
           'memory/shared_memory_android.cc',
+          'memory/shared_memory_handle.h',
+          'memory/shared_memory_handle_mac.cc',
+          'memory/shared_memory_handle_win.cc',
+          'memory/shared_memory_mac.cc',
           'memory/shared_memory_nacl.cc',
           'memory/shared_memory_posix.cc',
           'memory/shared_memory_win.cc',
@@ -364,10 +377,8 @@
           '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_loop_task_runner.cc',
+          'message_loop/message_loop_task_runner.h',
           'message_loop/message_pump.cc',
           'message_loop/message_pump.h',
           'message_loop/message_pump_android.cc',
@@ -391,6 +402,8 @@
           'metrics/histogram_samples.h',
           'metrics/histogram_snapshot_manager.cc',
           'metrics/histogram_snapshot_manager.h',
+          'metrics/metrics_hashes.cc',
+          'metrics/metrics_hashes.h',
           'metrics/sample_map.cc',
           'metrics/sample_map.h',
           'metrics/sample_vector.cc',
@@ -428,10 +441,11 @@
           'pending_task.h',
           'pickle.cc',
           'pickle.h',
-          'port.h',
           'posix/eintr_wrapper.h',
           'posix/global_descriptors.cc',
           'posix/global_descriptors.h',
+          'posix/safe_strerror.cc',
+          'posix/safe_strerror.h',
           'posix/unix_domain_socket_linux.cc',
           'posix/unix_domain_socket_linux.h',
           'power_monitor/power_monitor.cc',
@@ -466,7 +480,10 @@
           'process/memory_linux.cc',
           'process/memory_mac.mm',
           'process/memory_win.cc',
+          'process/port_provider_mac.cc',
+          'process/port_provider_mac.h',
           'process/process.h',
+          'process/process_handle.cc',
           'process/process_handle_freebsd.cc',
           'process/process_handle_linux.cc',
           'process/process_handle_mac.cc',
@@ -491,6 +508,7 @@
           'process/process_metrics_ios.cc',
           'process/process_metrics_linux.cc',
           'process/process_metrics_mac.cc',
+          'process/process_metrics_nacl.cc',
           'process/process_metrics_openbsd.cc',
           'process/process_metrics_posix.cc',
           'process/process_metrics_win.cc',
@@ -500,14 +518,14 @@
           'profiler/alternate_timer.h',
           'profiler/native_stack_sampler.cc',
           'profiler/native_stack_sampler.h',
+          'profiler/native_stack_sampler_posix.cc',
+          'profiler/native_stack_sampler_win.cc',
           'profiler/scoped_profile.cc',
           'profiler/scoped_profile.h',
           'profiler/scoped_tracker.cc',
           'profiler/scoped_tracker.h',
           'profiler/stack_sampling_profiler.cc',
           'profiler/stack_sampling_profiler.h',
-          'profiler/stack_sampling_profiler_posix.cc',
-          'profiler/stack_sampling_profiler_win.cc',
           'profiler/tracked_time.cc',
           'profiler/tracked_time.h',
           'rand_util.cc',
@@ -517,8 +535,6 @@
           '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',
@@ -538,6 +554,8 @@
           'strings/latin1_string_conversions.h',
           'strings/nullable_string16.cc',
           'strings/nullable_string16.h',
+          'strings/pattern.cc',
+          'strings/pattern.h',
           'strings/safe_sprintf.cc',
           'strings/safe_sprintf.h',
           'strings/string16.cc',
@@ -631,6 +649,8 @@
           'threading/platform_thread_win.cc',
           'threading/post_task_and_reply_impl.cc',
           'threading/post_task_and_reply_impl.h',
+          'threading/sequenced_task_runner_handle.cc',
+          'threading/sequenced_task_runner_handle.h',
           'threading/sequenced_worker_pool.cc',
           'threading/sequenced_worker_pool.h',
           'threading/simple_thread.cc',
@@ -709,14 +729,14 @@
           '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/process_startup_helper.cc',
+          'win/process_startup_helper.h',
           'win/registry.cc',
           'win/registry.h',
           'win/resource_util.cc',
@@ -755,17 +775,22 @@
         'include_dirs': [
           '..',
         ],
-        'msvs_disabled_warnings': [
-          4018,
-        ],
         'target_conditions': [
+          ['OS == "mac" or OS == "ios"', {
+            'sources!': [
+              'memory/shared_memory_posix.cc',
+            ],
+          }],
+          ['OS == "ios"', {
+            'sources!': [
+               'memory/discardable_shared_memory.cc',
+               'memory/discardable_shared_memory.h',
+            ],
+          }],
           ['(<(desktop_linux) == 0 and <(chromeos) == 0) or >(nacl_untrusted_build)==1', {
               'sources/': [
                 ['exclude', '^nix/'],
               ],
-              'sources!': [
-                'atomicops_internals_x86_gcc.cc',
-              ],
           }],
           ['<(use_glib)==0 or >(nacl_untrusted_build)==1', {
               'sources!': [
@@ -781,8 +806,6 @@
           ],
           ['>(nacl_untrusted_build)==1', {
             'sources!': [
-               'allocator/type_profiler_control.cc',
-               'allocator/type_profiler_control.h',
                'base_paths.cc',
                'cpu.cc',
                'debug/stack_trace.cc',
@@ -845,12 +868,8 @@
             ],
           }],
           ['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$'],
             ],
           }],
@@ -868,6 +887,7 @@
               ['include', '^files/file_util_mac\\.'],
               ['include', '^file_version_info_mac\\.'],
               ['include', '^mac/bundle_locations\\.'],
+              ['include', '^mac/call_with_eh_frame\\.'],
               ['include', '^mac/foundation_util\\.'],
               ['include', '^mac/mac_logging\\.'],
               ['include', '^mac/mach_logging\\.'],
@@ -877,6 +897,7 @@
               ['include', '^mac/scoped_nsautorelease_pool\\.'],
               ['include', '^mac/scoped_nsobject\\.'],
               ['include', '^mac/scoped_objc_class_swizzler\\.'],
+              ['include', '^memory/shared_memory_posix\\.'],
               ['include', '^message_loop/message_pump_mac\\.'],
               ['include', '^strings/sys_string_conversions_mac\\.'],
               ['include', '^threading/platform_thread_mac\\.'],
@@ -889,10 +910,9 @@
               ['include', '^process/memory_stubs\.cc$'],
               ['include', '^process/process_handle_posix\.cc$'],
               ['include', '^process/process_metrics\\.cc$'],
+              # Exclude unsupported features on iOS.
+              ['exclude', '^files/file_path_watcher.*'],
               ['exclude', '^threading/platform_thread_internal_posix\\.(h|cc)'],
-              ['exclude', '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',
@@ -927,6 +947,10 @@
             'include_dirs': [
               '<(DEPTH)/third_party/wtl/include',
             ],
+            'sources': [
+              'profiler/win32_stack_frame_unwinder.cc',
+              'profiler/win32_stack_frame_unwinder.h',
+            ],
             'sources!': [
               'files/file_path_watcher_fsevents.cc',
               'files/file_path_watcher_fsevents.h',
@@ -1012,6 +1036,8 @@
           'i18n/icu_string_conversions.h',
           'i18n/icu_util.cc',
           'i18n/icu_util.h',
+          'i18n/message_formatter.cc',
+          'i18n/message_formatter.h',
           'i18n/number_formatting.cc',
           'i18n/number_formatting.h',
           'i18n/rtl.cc',
diff --git a/base/base.isolate b/base/base.isolate
index c7ba651..e2d8bea 100644
--- a/base/base.isolate
+++ b/base/base.isolate
@@ -9,6 +9,8 @@
     '../third_party/icu/icu.isolate',
     # Sanitizer-instrumented third-party libraries (if enabled).
     '../third_party/instrumented_libraries/instrumented_libraries.isolate',
+    # MSVS runtime libraries.
+    '../build/config/win/msvs_dependencies.isolate',
   ],
   'conditions': [
     ['use_custom_libcxx==1', {
@@ -36,7 +38,9 @@
     ['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',
+          # We only need x.y.z/lib/windows/clang_rt.asan_dynamic-i386.dll,
+          # but since the version (x.y.z) changes, just grab the whole dir.
+          '../third_party/llvm-build/Release+Asserts/lib/clang/',
         ],
       },
     }],
@@ -56,40 +60,6 @@
         ],
       },
     }],
-    # 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/base64url.cc b/base/base64url.cc
new file mode 100644
index 0000000..106bba9
--- /dev/null
+++ b/base/base64url.cc
@@ -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.
+
+#include "base/base64url.h"
+
+#include "base/base64.h"
+#include "base/numerics/safe_math.h"
+#include "base/strings/string_util.h"
+#include "third_party/modp_b64/modp_b64.h"
+
+namespace base {
+
+const char kPaddingChar = '=';
+
+// Base64url maps {+, /} to {-, _} in order for the encoded content to be safe
+// to use in a URL. These characters will be translated by this implementation.
+const char kBase64Chars[] = "+/";
+const char kBase64UrlSafeChars[] = "-_";
+
+void Base64UrlEncode(const StringPiece& input,
+                     Base64UrlEncodePolicy policy,
+                     std::string* output) {
+  Base64Encode(input, output);
+
+  ReplaceChars(*output, "+", "-", output);
+  ReplaceChars(*output, "/", "_", output);
+
+  switch (policy) {
+    case Base64UrlEncodePolicy::INCLUDE_PADDING:
+      // The padding included in |*output| will not be amended.
+      break;
+    case Base64UrlEncodePolicy::OMIT_PADDING:
+      // The padding included in |*output| will be removed.
+      const size_t last_non_padding_pos =
+          output->find_last_not_of(kPaddingChar);
+      if (last_non_padding_pos != std::string::npos)
+        output->resize(last_non_padding_pos + 1);
+
+      break;
+  }
+}
+
+bool Base64UrlDecode(const StringPiece& input,
+                     Base64UrlDecodePolicy policy,
+                     std::string* output) {
+  // Characters outside of the base64url alphabet are disallowed, which includes
+  // the {+, /} characters found in the conventional base64 alphabet.
+  if (input.find_first_of(kBase64Chars) != std::string::npos)
+    return false;
+
+  const size_t required_padding_characters = input.size() % 4;
+  const bool needs_replacement =
+      input.find_first_of(kBase64UrlSafeChars) != std::string::npos;
+
+  switch (policy) {
+    case Base64UrlDecodePolicy::REQUIRE_PADDING:
+      // Fail if the required padding is not included in |input|.
+      if (required_padding_characters > 0)
+        return false;
+      break;
+    case Base64UrlDecodePolicy::IGNORE_PADDING:
+      // Missing padding will be silently appended.
+      break;
+    case Base64UrlDecodePolicy::DISALLOW_PADDING:
+      // Fail if padding characters are included in |input|.
+      if (input.find_first_of(kPaddingChar) != std::string::npos)
+        return false;
+      break;
+  }
+
+  // If the string either needs replacement of URL-safe characters to normal
+  // base64 ones, or additional padding, a copy of |input| needs to be made in
+  // order to make these adjustments without side effects.
+  if (required_padding_characters > 0 || needs_replacement) {
+    std::string base64_input;
+
+    CheckedNumeric<size_t> base64_input_size = input.size();
+    if (required_padding_characters > 0)
+      base64_input_size += 4 - required_padding_characters;
+
+    base64_input.reserve(base64_input_size.ValueOrDie());
+    input.AppendToString(&base64_input);
+
+    // Substitute the base64url URL-safe characters to their base64 equivalents.
+    ReplaceChars(base64_input, "-", "+", &base64_input);
+    ReplaceChars(base64_input, "_", "/", &base64_input);
+
+    // Append the necessary padding characters.
+    base64_input.resize(base64_input_size.ValueOrDie(), '=');
+
+    return Base64Decode(base64_input, output);
+  }
+
+  return Base64Decode(input, output);
+}
+
+}  // namespace base
diff --git a/base/base64url.h b/base/base64url.h
new file mode 100644
index 0000000..dd4c5a2
--- /dev/null
+++ b/base/base64url.h
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE64URL_H_
+#define BASE_BASE64URL_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+enum class Base64UrlEncodePolicy {
+  // Include the trailing padding in the output, when necessary.
+  INCLUDE_PADDING,
+
+  // Remove the trailing padding from the output.
+  OMIT_PADDING
+};
+
+// Encodes the |input| string in base64url, defined in RFC 4648:
+// https://tools.ietf.org/html/rfc4648#section-5
+//
+// The |policy| defines whether padding should be included or omitted from the
+// encoded |*output|. |input| and |*output| may reference the same storage.
+BASE_EXPORT void Base64UrlEncode(const StringPiece& input,
+                                 Base64UrlEncodePolicy policy,
+                                 std::string* output);
+
+enum class Base64UrlDecodePolicy {
+  // Require inputs contain trailing padding if non-aligned.
+  REQUIRE_PADDING,
+
+  // Accept inputs regardless of whether or not they have the correct padding.
+  IGNORE_PADDING,
+
+  // Reject inputs if they contain any trailing padding.
+  DISALLOW_PADDING
+};
+
+// Decodes the |input| string in base64url, defined in RFC 4648:
+// https://tools.ietf.org/html/rfc4648#section-5
+//
+// The |policy| defines whether padding will be required, ignored or disallowed
+// altogether. |input| and |*output| may reference the same storage.
+BASE_EXPORT bool Base64UrlDecode(const StringPiece& input,
+                                 Base64UrlDecodePolicy policy,
+                                 std::string* output) WARN_UNUSED_RESULT;
+
+}  // namespace base
+
+#endif  // BASE_BASE64URL_H_
diff --git a/base/base64url_unittest.cc b/base/base64url_unittest.cc
new file mode 100644
index 0000000..489c174
--- /dev/null
+++ b/base/base64url_unittest.cc
@@ -0,0 +1,114 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base64url.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+TEST(Base64UrlTest, EncodeIncludePaddingPolicy) {
+  std::string output;
+  Base64UrlEncode("hello?world", Base64UrlEncodePolicy::INCLUDE_PADDING,
+                  &output);
+
+  // Base64 version: aGVsbG8/d29ybGQ=
+  EXPECT_EQ("aGVsbG8_d29ybGQ=", output);
+
+  // Test for behavior for very short and empty strings.
+  Base64UrlEncode("??", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
+  EXPECT_EQ("Pz8=", output);
+
+  Base64UrlEncode("", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
+  EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, EncodeOmitPaddingPolicy) {
+  std::string output;
+  Base64UrlEncode("hello?world", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+
+  // base64 version: aGVsbG8/d29ybGQ=
+  EXPECT_EQ("aGVsbG8_d29ybGQ", output);
+
+  // Test for behavior for very short and empty strings.
+  Base64UrlEncode("??", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+  EXPECT_EQ("Pz8", output);
+
+  Base64UrlEncode("", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+  EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, DecodeRequirePaddingPolicy) {
+  std::string output;
+  ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
+                              Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+
+  EXPECT_EQ("hello?world", output);
+
+  ASSERT_FALSE(Base64UrlDecode(
+      "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+
+  // Test for behavior for very short and empty strings.
+  ASSERT_TRUE(
+      Base64UrlDecode("Pz8=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+  EXPECT_EQ("??", output);
+
+  ASSERT_TRUE(
+      Base64UrlDecode("", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+  EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, DecodeIgnorePaddingPolicy) {
+  std::string output;
+  ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ",
+                              Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+
+  EXPECT_EQ("hello?world", output);
+
+  // Including the padding is accepted as well.
+  ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
+                              Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+
+  EXPECT_EQ("hello?world", output);
+}
+
+TEST(Base64UrlTest, DecodeDisallowPaddingPolicy) {
+  std::string output;
+  ASSERT_FALSE(Base64UrlDecode(
+      "aGVsbG8_d29ybGQ=", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
+
+  // The policy will allow the input when padding has been omitted.
+  ASSERT_TRUE(Base64UrlDecode(
+      "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
+
+  EXPECT_EQ("hello?world", output);
+}
+
+TEST(Base64UrlTest, DecodeDisallowsBase64Alphabet) {
+  std::string output;
+
+  // The "/" character is part of the conventional base64 alphabet, but has been
+  // substituted with "_" in the base64url alphabet.
+  ASSERT_FALSE(Base64UrlDecode(
+      "aGVsbG8/d29ybGQ=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+}
+
+TEST(Base64UrlTest, DecodeDisallowsPaddingOnly) {
+  std::string output;
+
+  ASSERT_FALSE(Base64UrlDecode(
+      "=", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+  ASSERT_FALSE(Base64UrlDecode(
+      "==", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+  ASSERT_FALSE(Base64UrlDecode(
+      "===", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+  ASSERT_FALSE(Base64UrlDecode(
+      "====", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/base_export.h b/base/base_export.h
index 723b38a..cf7ebd7 100644
--- a/base/base_export.h
+++ b/base/base_export.h
@@ -10,25 +10,20 @@
 
 #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
index 40005d2..b2b4b7f 100644
--- a/base/base_nacl.gyp
+++ b/base/base_nacl.gyp
@@ -35,7 +35,7 @@
               'sync_socket_nacl.cc',
               'time/time_posix.cc',
             ],
-            'gcc_compile_flags': [
+            'compile_flags': [
               '-fno-strict-aliasing',
             ],
           },
@@ -83,6 +83,7 @@
               'base_switches.h',
 
               # For PathExists and ReadFromFD.
+              'files/file_util.cc',
               'files/file_util_posix.cc',
 
               # For MessageLoopForIO based on libevent.
@@ -95,6 +96,10 @@
               # For GetKnownDeadTerminationStatus and GetTerminationStatus.
               'process/kill_posix.cc',
 
+              # For ForkWithFlags.
+              'process/launch.h',
+              'process/launch_posix.cc',
+
               # Unlike libbase_nacl, for Non-SFI build, we need to use
               # rand_util_posix for random implementation, instead of
               # rand_util_nacl.cc, which is based on IRT. rand_util_nacl.cc is
@@ -112,6 +117,30 @@
             '../third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
           ],
         },
+        {
+          'target_name': 'test_support_base_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libtest_support_base_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+
+            'sources': [
+              'test/gtest_util.cc',
+              'test/launcher/unit_test_launcher_nacl_nonsfi.cc',
+              'test/gtest_xml_unittest_result_printer.cc',
+              'test/test_switches.cc',
+            ],
+          },
+          'dependencies': [
+            'base_nacl_nonsfi',
+            '../testing/gtest_nacl.gyp:gtest_nacl',
+          ],
+        },
       ],
     }],
   ],
diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm
index 9864eb3..af4bd1a 100644
--- a/base/base_paths_mac.mm
+++ b/base/base_paths_mac.mm
@@ -29,8 +29,9 @@
   _NSGetExecutablePath(NULL, &executable_length);
   DCHECK_GT(executable_length, 1u);
   std::string executable_path;
-  int rv = _NSGetExecutablePath(WriteInto(&executable_path, executable_length),
-                                &executable_length);
+  int rv = _NSGetExecutablePath(
+      base::WriteInto(&executable_path, executable_length),
+                      &executable_length);
   DCHECK_EQ(rv, 0);
 
   // _NSGetExecutablePath may return paths containing ./ or ../ which makes
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc
index 4ecb59d..58f925f 100644
--- a/base/base_paths_win.cc
+++ b/base/base_paths_win.cc
@@ -32,14 +32,16 @@
   FilePath cur;
   switch (key) {
     case base::FILE_EXE:
-      GetModuleFileName(NULL, system_buffer, MAX_PATH);
+      if (GetModuleFileName(NULL, system_buffer, MAX_PATH) == 0)
+        return false;
       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);
+      if (GetModuleFileName(this_module, system_buffer, MAX_PATH) == 0)
+        return false;
       cur = FilePath(system_buffer);
       break;
     }
diff --git a/base/base_paths_win.h b/base/base_paths_win.h
index 9ac9e45..d9dbc39 100644
--- a/base/base_paths_win.h
+++ b/base/base_paths_win.h
@@ -42,8 +42,8 @@
   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_TASKBAR_PINS,       // Directory for the shortcuts pinned to taskbar
+                          // (Win7-8) via base::win::PinShortcutToTaskbar().
   DIR_WINDOWS_FONTS,      // Usually C:\Windows\Fonts.
 
   PATH_WIN_END
diff --git a/base/base_switches.cc b/base/base_switches.cc
index 3076540..b7835c0 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -14,6 +14,11 @@
 // generated internally.
 const char kEnableCrashReporter[]           = "enable-crash-reporter";
 
+// Makes memory allocators keep track of their allocations and context, so a
+// detailed breakdown of memory usage can be presented in chrome://tracing when
+// the memory-infra category is enabled.
+const char kEnableHeapProfiling[]           = "enable-heap-profiling";
+
 // Generates full memory crash dump.
 const char kFullMemoryCrashReport[]         = "full-memory-crash-report";
 
@@ -23,6 +28,16 @@
 // Force disabling of low-end device mode when set.
 const char kDisableLowEndDeviceMode[]       = "disable-low-end-device-mode";
 
+// This option can be used to force field trials when testing changes locally.
+// The argument is a list of name and value pairs, separated by slashes. If a
+// trial name is prefixed with an asterisk, that trial will start activated.
+// For example, the following argument defines two trials, with the second one
+// activated: "GoogleNow/Enable/*MaterialDesignNTP/Default/" This option can
+// also be used by the browser process to send the list of trials to a
+// non-browser process, using the same format. See
+// FieldTrialList::CreateTrialsFromString() in field_trial.h for details.
+const char kForceFieldTrials[]              = "force-fieldtrials";
+
 // Suppresses all error dialogs when present.
 const char kNoErrorDialogs[]                = "noerrdialogs";
 
@@ -67,6 +82,11 @@
 // chrome://profiler.
 const char kProfilerTimingDisabledValue[]   = "0";
 
+#if defined(OS_WIN)
+// Disables the USB keyboard detection for blocking the OSK on Win8+.
+const char kDisableUsbKeyboardDetect[]      = "disable-usb-keyboard-detect";
+#endif
+
 #if defined(OS_POSIX)
 // Used for turning on Breakpad crash reporting in a debug environment where
 // crash reporting is typically compiled but disabled.
diff --git a/base/base_switches.h b/base/base_switches.h
index c579f6a..9c1eaf4 100644
--- a/base/base_switches.h
+++ b/base/base_switches.h
@@ -12,10 +12,12 @@
 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 kEnableCrashReporter[];
+extern const char kEnableHeapProfiling[];
+extern const char kEnableLowEndDeviceMode[];
+extern const char kForceFieldTrials[];
+extern const char kFullMemoryCrashReport[];
 extern const char kNoErrorDialogs[];
 extern const char kProfilerTiming[];
 extern const char kProfilerTimingDisabledValue[];
@@ -27,6 +29,10 @@
 extern const char kVModule[];
 extern const char kWaitForDebugger[];
 
+#if defined(OS_WIN)
+extern const char kDisableUsbKeyboardDetect[];
+#endif
+
 #if defined(OS_POSIX)
 extern const char kEnableCrashReporterForTesting[];
 #endif
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
index b1c270c..208501f 100644
--- a/base/base_unittests.isolate
+++ b/base/base_unittests.isolate
@@ -2,38 +2,18 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 {
+  'variables': {
+    'command': [
+      '../testing/test_env.py',
+      '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+      '--brave-new-test-launcher',
+      '--test-launcher-bot-mode',
+      '--asan=<(asan)',
+      '--msan=<(msan)',
+      '--tsan=<(tsan)',
+    ],
+  },
   'conditions': [
-    ['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': [
@@ -45,9 +25,7 @@
       'variables': {
         'files': [
           '../testing/test_env.py',
-          '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
         ],
-        'read_only': 1,
       },
     }],
     ['OS=="linux"', {
diff --git a/base/base_unittests_apk.isolate b/base/base_unittests_apk.isolate
new file mode 100644
index 0000000..425c779
--- /dev/null
+++ b/base/base_unittests_apk.isolate
@@ -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.
+{
+  'includes': [
+    '../build/android/android.isolate',
+    'base_unittests.isolate',
+  ],
+  'variables': {
+    'command': [
+      '<(PRODUCT_DIR)/bin/run_base_unittests',
+    ],
+    'files': [
+      '../build/config/',
+      '../third_party/icu/icu.isolate',
+      '../third_party/instrumented_libraries/instrumented_libraries.isolate',
+      '<(PRODUCT_DIR)/base_unittests_apk/',
+      '<(PRODUCT_DIR)/bin/run_base_unittests',
+      '<(PRODUCT_DIR)/icudtl.dat',
+      'base.isolate',
+      'base_unittests.isolate',
+    ]
+  },
+}
diff --git a/base/basictypes.h b/base/basictypes.h
index bf75e67..7607735 100644
--- a/base/basictypes.h
+++ b/base/basictypes.h
@@ -2,12 +2,6 @@
 // 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_
 
@@ -16,9 +10,10 @@
 #include <stdint.h>  // For intptr_t.
 
 #include "base/macros.h"
-#include "base/port.h"  // Types that only need exist on certain systems.
+#include "build/build_config.h"
 
-// DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
+// DEPRECATED: Use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
+// http://crbug.com/138542
 typedef int8_t int8;
 typedef uint8_t uint8;
 typedef int16_t int16;
@@ -28,15 +23,12 @@
 typedef int64_t int64;
 typedef uint64_t uint64;
 
-// DEPRECATED: Please use std::numeric_limits (from <limits>) instead.
+// DEPRECATED: Use std::numeric_limits (from <limits>) or
+// (U)INT{8,16,32,64}_{MIN,MAX} in case of globals (and include <stdint.h>).
+// http://crbug.com/138542
 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;
diff --git a/base/bind.h b/base/bind.h
index 51be10d..94da5ac 100644
--- a/base/bind.h
+++ b/base/bind.h
@@ -89,7 +89,7 @@
   // 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");
+                "do not bind functions with nonconst ref");
 
   const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
 
@@ -98,10 +98,10 @@
   // 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");
+                "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");
+      "a parameter is a refcounted type and needs scoped_refptr");
 
   typedef internal::BindState<
       RunnableType, RunType,
diff --git a/base/bind_internal.h b/base/bind_internal.h
index e053218..c6832e6 100644
--- a/base/bind_internal.h
+++ b/base/bind_internal.h
@@ -5,6 +5,8 @@
 #ifndef BASE_BIND_INTERNAL_H_
 #define BASE_BIND_INTERNAL_H_
 
+#include <type_traits>
+
 #include "base/bind_helpers.h"
 #include "base/callback_internal.h"
 #include "base/memory/raw_scoped_refptr_mismatch_checker.h"
@@ -77,9 +79,9 @@
 // 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 {};
+    : std::conditional<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.
@@ -93,9 +95,9 @@
 // parameters recursively.
 template <typename T, typename... Args>
 struct HasRefCountedTypeAsRawPtr<T, Args...>
-    : SelectType<NeedsScopedRefptrButGetsRawPtr<T>::value,
-                 true_type,
-                 HasRefCountedTypeAsRawPtr<Args...>>::Type {};
+    : std::conditional<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.
@@ -311,8 +313,8 @@
   // 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);
+  static_assert(is_void<ReturnType>::value,
+                "weak_ptrs can only bind to methods without return values");
 };
 
 #endif
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc
index 2596386..7c79611 100644
--- a/base/bind_unittest.nc
+++ b/base/bind_unittest.nc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
 #include "base/callback.h"
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
diff --git a/base/bits.h b/base/bits.h
index b2209e8..505d2c8 100644
--- a/base/bits.h
+++ b/base/bits.h
@@ -41,6 +41,12 @@
   }
 }
 
+// Round up |size| to a multiple of alignment, which must be a power of two.
+inline size_t Align(size_t size, size_t alignment) {
+  DCHECK_EQ(alignment & (alignment - 1), 0u);
+  return (size + alignment - 1) & ~(alignment - 1);
+}
+
 }  // namespace bits
 }  // namespace base
 
diff --git a/base/bits_unittest.cc b/base/bits_unittest.cc
index e913d6a..1dad0f4 100644
--- a/base/bits_unittest.cc
+++ b/base/bits_unittest.cc
@@ -5,6 +5,9 @@
 // This file contains the unit tests for the bit utilities.
 
 #include "base/bits.h"
+
+#include <limits>
+
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -44,5 +47,17 @@
   EXPECT_EQ(32, Log2Ceiling(0xffffffffU));
 }
 
+TEST(BitsTest, Align) {
+  const size_t kSizeTMax = std::numeric_limits<size_t>::max();
+  EXPECT_EQ(0ul, Align(0, 4));
+  EXPECT_EQ(4ul, Align(1, 4));
+  EXPECT_EQ(4096ul, Align(1, 4096));
+  EXPECT_EQ(4096ul, Align(4096, 4096));
+  EXPECT_EQ(4096ul, Align(4095, 4096));
+  EXPECT_EQ(8192ul, Align(4097, 4096));
+  EXPECT_EQ(kSizeTMax - 31, Align(kSizeTMax - 62, 32));
+  EXPECT_EQ(kSizeTMax / 2 + 1, Align(1, kSizeTMax / 2 + 1));
+}
+
 }  // namespace bits
 }  // namespace base
diff --git a/base/callback_internal.h b/base/callback_internal.h
index fefd7a2..8f0c2b3 100644
--- a/base/callback_internal.h
+++ b/base/callback_internal.h
@@ -9,6 +9,7 @@
 #define BASE_CALLBACK_INTERNAL_H_
 
 #include <stddef.h>
+#include <type_traits>
 
 #include "base/atomic_ref_count.h"
 #include "base/base_export.h"
@@ -17,9 +18,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/template_util.h"
 
-template <typename T>
-class ScopedVector;
-
 namespace base {
 namespace internal {
 class CallbackBase;
@@ -108,18 +106,6 @@
                             !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;
 
@@ -143,9 +129,9 @@
 // break passing of C-string literals.
 template <typename T>
 struct CallbackParamTraits
-    : SelectType<IsMoveOnlyType<T>::value,
+    : std::conditional<IsMoveOnlyType<T>::value,
          CallbackParamTraitsForMoveOnlyType<T>,
-         CallbackParamTraitsForNonMoveOnlyType<T> >::Type {
+         CallbackParamTraitsForNonMoveOnlyType<T>>::type {
 };
 
 template <typename T>
@@ -219,12 +205,14 @@
 // 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) {
+typename std::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) {
+typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(
+    T& t) {
   return t.Pass();
 }
 
diff --git a/base/callback_list.h b/base/callback_list.h
index aeed5f1..5f263f8 100644
--- a/base/callback_list.h
+++ b/base/callback_list.h
@@ -185,10 +185,10 @@
       } else {
         ++it;
       }
-
-      if (updated && !removal_callback_.is_null())
-        removal_callback_.Run();
     }
+
+    if (updated && !removal_callback_.is_null())
+      removal_callback_.Run();
   }
 
  private:
diff --git a/base/callback_list_unittest.cc b/base/callback_list_unittest.cc
index 9adbabb..1cae827 100644
--- a/base/callback_list_unittest.cc
+++ b/base/callback_list_unittest.cc
@@ -98,6 +98,19 @@
   DISALLOW_COPY_AND_ASSIGN(Summer);
 };
 
+class Counter {
+ public:
+  Counter() : value_(0) {}
+
+  void Increment() { value_++; }
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+  DISALLOW_COPY_AND_ASSIGN(Counter);
+};
+
 // Sanity check that we can instantiate a CallbackList for each arity.
 TEST(CallbackListTest, ArityTest) {
   Summer s;
@@ -287,5 +300,37 @@
   cb_reg.Notify();
 }
 
+TEST(CallbackList, RemovalCallback) {
+  Counter remove_count;
+  CallbackList<void(void)> cb_reg;
+  cb_reg.set_removal_callback(
+      Bind(&Counter::Increment, Unretained(&remove_count)));
+
+  scoped_ptr<CallbackList<void(void)>::Subscription> subscription =
+      cb_reg.Add(Bind(&DoNothing));
+
+  // Removing a subscription outside of iteration signals the callback.
+  EXPECT_EQ(0, remove_count.value());
+  subscription.reset();
+  EXPECT_EQ(1, remove_count.value());
+
+  // Configure two subscriptions to remove themselves.
+  Remover remover_1, remover_2;
+  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)));
+  remover_1.SetSubscriptionToRemove(remover_1_sub.Pass());
+  remover_2.SetSubscriptionToRemove(remover_2_sub.Pass());
+
+  // The callback should be signaled exactly once.
+  EXPECT_EQ(1, remove_count.value());
+  cb_reg.Notify();
+  EXPECT_EQ(2, remove_count.value());
+  EXPECT_TRUE(cb_reg.empty());
+}
+
 }  // namespace
 }  // namespace base
diff --git a/base/callback_list_unittest.nc b/base/callback_list_unittest.nc
index 2d464cf..08acce6 100644
--- a/base/callback_list_unittest.nc
+++ b/base/callback_list_unittest.nc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
 #include "base/callback_list.h"
 
 #include "base/basictypes.h"
diff --git a/base/callback_unittest.nc b/base/callback_unittest.nc
index e7607d9..edf26b7 100644
--- a/base/callback_unittest.nc
+++ b/base/callback_unittest.nc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
 #include "base/callback.h"
 
 namespace base {
diff --git a/base/chromeos/OWNERS b/base/chromeos/OWNERS
deleted file mode 100644
index 8fda46a..0000000
--- a/base/chromeos/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-skuhne@chromium.org
-oshima@chromium.org
-
diff --git a/base/command_line.cc b/base/command_line.cc
index 61ff5c1..c2ce33d 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -93,18 +93,6 @@
   }
 }
 
-// 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,
@@ -180,6 +168,21 @@
   InitFromArgv(argv);
 }
 
+CommandLine::CommandLine(const CommandLine& other)
+    : argv_(other.argv_),
+      switches_(other.switches_),
+      begin_args_(other.begin_args_) {
+  ResetStringPieces();
+}
+
+CommandLine& CommandLine::operator=(const CommandLine& other) {
+  argv_ = other.argv_;
+  switches_ = other.switches_;
+  begin_args_ = other.begin_args_;
+  ResetStringPieces();
+  return *this;
+}
+
 CommandLine::~CommandLine() {
 }
 
@@ -249,6 +252,7 @@
 void CommandLine::InitFromArgv(const StringVector& argv) {
   argv_ = StringVector(1);
   switches_.clear();
+  switches_by_stringpiece_.clear();
   begin_args_ = 1;
   SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
   AppendSwitchesAndArguments(this, argv);
@@ -262,17 +266,18 @@
   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 base::StringPiece& switch_string) const {
+  DCHECK_EQ(ToLowerASCII(switch_string), switch_string);
+  return switches_by_stringpiece_.find(switch_string) !=
+         switches_by_stringpiece_.end();
 }
 
-bool CommandLine::HasSwitch(const char string_constant[]) const {
-  return HasSwitch(std::string(string_constant));
+bool CommandLine::HasSwitch(const char switch_constant[]) const {
+  return HasSwitch(base::StringPiece(switch_constant));
 }
 
 std::string CommandLine::GetSwitchValueASCII(
-    const std::string& switch_string) const {
+    const base::StringPiece& switch_string) const {
   StringType value = GetSwitchValueNative(switch_string);
   if (!IsStringASCII(value)) {
     DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII.";
@@ -286,15 +291,16 @@
 }
 
 FilePath CommandLine::GetSwitchValuePath(
-    const std::string& switch_string) const {
+    const base::StringPiece& 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;
+    const base::StringPiece& switch_string) const {
+  DCHECK_EQ(ToLowerASCII(switch_string), switch_string);
+  auto result = switches_by_stringpiece_.find(switch_string);
+  return result == switches_by_stringpiece_.end() ? StringType()
+                                                  : *(result->second);
 }
 
 void CommandLine::AppendSwitch(const std::string& switch_string) {
@@ -308,14 +314,19 @@
 
 void CommandLine::AppendSwitchNative(const std::string& switch_string,
                                      const CommandLine::StringType& value) {
-  std::string switch_key(LowerASCIIOnWindows(switch_string));
 #if defined(OS_WIN)
+  const std::string switch_key = ToLowerASCII(switch_string);
   StringType combined_switch_string(ASCIIToUTF16(switch_key));
 #elif defined(OS_POSIX)
-  StringType combined_switch_string(switch_string);
+  const std::string& switch_key = switch_string;
+  StringType combined_switch_string(switch_key);
 #endif
   size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
-  switches_[switch_key.substr(prefix_length)] = value;
+  auto insertion =
+      switches_.insert(make_pair(switch_key.substr(prefix_length), value));
+  if (!insertion.second)
+    insertion.first->second = value;
+  switches_by_stringpiece_[insertion.first->first] = &(insertion.first->second);
   // Preserve existing switch prefixes in |argv_|; only append one if necessary.
   if (prefix_length == 0)
     combined_switch_string = kSwitchPrefixes[0] + combined_switch_string;
@@ -383,8 +394,9 @@
     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);
+  StringVector wrapper_argv = SplitString(
+      wrapper, FilePath::StringType(1, ' '), base::TRIM_WHITESPACE,
+      base::SPLIT_WANT_ALL);
   // Prepend the wrapper and update the switches/arguments |begin_args_|.
   argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end());
   begin_args_ += wrapper_argv.size();
@@ -453,4 +465,10 @@
   return params;
 }
 
+void CommandLine::ResetStringPieces() {
+  switches_by_stringpiece_.clear();
+  for (const auto& entry : switches_)
+    switches_by_stringpiece_[entry.first] = &(entry.second);
+}
+
 }  // namespace base
diff --git a/base/command_line.h b/base/command_line.h
index 439921e..3de8873 100644
--- a/base/command_line.h
+++ b/base/command_line.h
@@ -22,6 +22,7 @@
 
 #include "base/base_export.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
 #include "build/build_config.h"
 
 namespace base {
@@ -40,6 +41,7 @@
   typedef StringType::value_type CharType;
   typedef std::vector<StringType> StringVector;
   typedef std::map<std::string, StringType> SwitchMap;
+  typedef std::map<base::StringPiece, const StringType*> StringPieceSwitchMap;
 
   // A constructor for CommandLines that only carry switches and arguments.
   enum NoProgram { NO_PROGRAM };
@@ -52,6 +54,10 @@
   CommandLine(int argc, const CharType* const* argv);
   explicit CommandLine(const StringVector& argv);
 
+  // Override copy and assign to ensure |switches_by_stringpiece_| is valid.
+  CommandLine(const CommandLine& other);
+  CommandLine& operator=(const CommandLine& other);
+
   ~CommandLine();
 
 #if defined(OS_WIN)
@@ -142,17 +148,19 @@
   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;
+  // Switch names must be lowercase.
+  // The second override provides an optimized version to avoid inlining codegen
+  // at every callsite to find the length of the constant and construct a
+  // StringPiece.
+  bool HasSwitch(const base::StringPiece& switch_string) const;
   bool HasSwitch(const char switch_constant[]) const;
 
   // Returns the value associated with the given switch. If the switch has no
   // value or isn't present, this method returns the empty string.
-  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;
+  // Switch names must be lowercase.
+  std::string GetSwitchValueASCII(const base::StringPiece& switch_string) const;
+  FilePath GetSwitchValuePath(const base::StringPiece& switch_string) const;
+  StringType GetSwitchValueNative(const base::StringPiece& switch_string) const;
 
   // Get a copy of all switches, along with their values.
   const SwitchMap& GetSwitches() const { return switches_; }
@@ -214,6 +222,11 @@
   // also quotes parts with '%' in them.
   StringType GetArgumentsStringInternal(bool quote_placeholders) const;
 
+  // Reconstruct |switches_by_stringpiece| to be a mirror of |switches|.
+  // |switches_by_stringpiece| only contains pointers to objects owned by
+  // |switches|.
+  void ResetStringPieces();
+
   // The singleton CommandLine representing the current process's command line.
   static CommandLine* current_process_commandline_;
 
@@ -223,6 +236,12 @@
   // Parsed-out switch keys and values.
   SwitchMap switches_;
 
+  // A mirror of |switches_| with only references to the actual strings.
+  // The StringPiece internally holds a pointer to a key in |switches_| while
+  // the mapped_type points to a value in |switches_|.
+  // Used for allocation-free lookups.
+  StringPieceSwitchMap switches_by_stringpiece_;
+
   // The index after the program and switches, any arguments start here.
   size_t begin_args_;
 };
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index db1a0b2..ac8a395 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -71,7 +72,7 @@
   EXPECT_TRUE(cl.HasSwitch("input-translation"));
 
   EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
-  EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
   EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
   EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
   EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
@@ -134,7 +135,7 @@
   EXPECT_TRUE(cl.HasSwitch("quotes"));
 
   EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
-  EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
   EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
   EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
   EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
@@ -273,6 +274,7 @@
   cl.AppendSwitchASCII(switch2, value2);
   cl.AppendSwitchASCII(switch3, value3);
   cl.AppendSwitchASCII(switch4, value4);
+  cl.AppendSwitchASCII(switch5, value4);
   cl.AppendSwitchNative(switch5, value5);
 
   EXPECT_TRUE(cl.HasSwitch(switch1));
@@ -291,6 +293,9 @@
             L"--switch2=value "
             L"--switch3=\"a value with spaces\" "
             L"--switch4=\"\\\"a value with quotes\\\"\" "
+            // Even though the switches are unique, appending can add repeat
+            // switches to argv.
+            L"--quotes=\"\\\"a value with quotes\\\"\" "
             L"--quotes=\"" + kTrickyQuoted + L"\"",
             cl.GetCommandLineString());
 #endif
@@ -373,10 +378,29 @@
 
 // Calling Init multiple times should not modify the previous CommandLine.
 TEST(CommandLineTest, Init) {
+  // Call Init without checking output once so we know it's been called
+  // whether or not the test runner does so.
+  CommandLine::Init(0, NULL);
   CommandLine* initial = CommandLine::ForCurrentProcess();
   EXPECT_FALSE(CommandLine::Init(0, NULL));
   CommandLine* current = CommandLine::ForCurrentProcess();
   EXPECT_EQ(initial, current);
 }
 
+// Test that copies of CommandLine have a valid StringPiece map.
+TEST(CommandLineTest, Copy) {
+  scoped_ptr<CommandLine> initial(new CommandLine(CommandLine::NO_PROGRAM));
+  initial->AppendSwitch("a");
+  initial->AppendSwitch("bbbbbbbbbbbbbbb");
+  initial->AppendSwitch("c");
+  CommandLine copy_constructed(*initial);
+  CommandLine assigned = *initial;
+  CommandLine::SwitchMap switch_map = initial->GetSwitches();
+  initial.reset();
+  for (const auto& pair : switch_map)
+    EXPECT_TRUE(copy_constructed.HasSwitch(pair.first));
+  for (const auto& pair : switch_map)
+    EXPECT_TRUE(assigned.HasSwitch(pair.first));
+}
+
 } // namespace base
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 63297dc..402bc5d 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -9,6 +9,9 @@
 
 #if defined(COMPILER_MSVC)
 
+// For _Printf_format_string_.
+#include <sal.h>
+
 // Macros for suppressing and disabling warnings on MSVC.
 //
 // Warning numbers are enumerated at:
@@ -57,6 +60,7 @@
 
 #else  // Not MSVC
 
+#define _Printf_format_string_
 #define MSVC_SUPPRESS_WARNING(n)
 #define MSVC_PUSH_DISABLE_WARNING(n)
 #define MSVC_PUSH_WARNING_LEVEL(n)
@@ -68,28 +72,6 @@
 #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.)
@@ -101,7 +83,7 @@
 // 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)
+#if defined(COMPILER_GCC) || defined(__clang__)
 #define ALLOW_UNUSED_TYPE __attribute__((unused))
 #else
 #define ALLOW_UNUSED_TYPE
@@ -140,8 +122,10 @@
 // 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)
+// To explicitly ignore a result, see |ignore_result()| in base/macros.h.
+// TODO(dcheng): Update //third_party/webrtc's macro definition to match.
+#undef WARN_UNUSED_RESULT
+#if defined(COMPILER_GCC) || defined(__clang__)
 #define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
 #else
 #define WARN_UNUSED_RESULT
diff --git a/base/containers/adapters.h b/base/containers/adapters.h
index cc151fc..fa671b4 100644
--- a/base/containers/adapters.h
+++ b/base/containers/adapters.h
@@ -5,6 +5,10 @@
 #ifndef BASE_CONTAINERS_ADAPTERS_H_
 #define BASE_CONTAINERS_ADAPTERS_H_
 
+#include <stddef.h>
+
+#include <iterator>
+
 #include "base/macros.h"
 
 namespace base {
@@ -15,11 +19,13 @@
 template <typename T>
 class ReversedAdapter {
  public:
-  typedef decltype(static_cast<T*>(nullptr)->rbegin()) Iterator;
+  using Iterator = decltype(static_cast<T*>(nullptr)->rbegin());
 
   explicit ReversedAdapter(T& t) : t_(t) {}
   ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
 
+  // TODO(mdempsky): Once we can use C++14 library features, use std::rbegin
+  // and std::rend instead, so we can remove the specialization below.
   Iterator begin() const { return t_.rbegin(); }
   Iterator end() const { return t_.rend(); }
 
@@ -29,6 +35,23 @@
   DISALLOW_ASSIGN(ReversedAdapter);
 };
 
+template <typename T, size_t N>
+class ReversedAdapter<T[N]> {
+ public:
+  using Iterator = std::reverse_iterator<T*>;
+
+  explicit ReversedAdapter(T (&t)[N]) : t_(t) {}
+  ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+
+  Iterator begin() const { return Iterator(&t_[N]); }
+  Iterator end() const { return Iterator(&t_[0]); }
+
+ private:
+  T (&t_)[N];
+
+  DISALLOW_ASSIGN(ReversedAdapter);
+};
+
 }  // namespace internal
 
 // Reversed returns a container adapter usable in a range-based "for" statement
diff --git a/base/containers/adapters_unittest.cc b/base/containers/adapters_unittest.cc
index 4c87472..92554b7 100644
--- a/base/containers/adapters_unittest.cc
+++ b/base/containers/adapters_unittest.cc
@@ -25,7 +25,19 @@
   EXPECT_EQ(101, v[2]);
 }
 
-TEST(AdaptersTest, ConstReversed) {
+TEST(AdaptersTest, ReversedArray) {
+  int v[3] = {3, 2, 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, ReversedConst) {
   std::vector<int> v;
   v.push_back(3);
   v.push_back(2);
diff --git a/base/containers/hash_tables.h b/base/containers/hash_tables.h
index 5ce9161..a1244f7 100644
--- a/base/containers/hash_tables.h
+++ b/base/containers/hash_tables.h
@@ -247,57 +247,16 @@
   return high_bits;
 }
 
-#define DEFINE_32BIT_PAIR_HASH(Type1, Type2) \
-inline std::size_t HashPair(Type1 value1, Type2 value2) { \
-  return HashInts32(value1, value2); \
+template<typename T1, typename T2>
+inline std::size_t HashPair(T1 value1, T2 value2) {
+  // This condition is expected to be compile-time evaluated and optimised away
+  // in release builds.
+  if (sizeof(T1) > sizeof(uint32_t) || (sizeof(T2) > sizeof(uint32_t)))
+    return HashInts64(value1, value2);
+
+  return HashInts32(value1, value2);
 }
 
-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 {
diff --git a/base/containers/hash_tables_unittest.cc b/base/containers/hash_tables_unittest.cc
index 60fbeaa..f775dff 100644
--- a/base/containers/hash_tables_unittest.cc
+++ b/base/containers/hash_tables_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/containers/hash_tables.h"
 
+#include <stdint.h>
 #include <string>
 
 #include "base/basictypes.h"
@@ -31,7 +32,7 @@
   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));
+                   (INT64_C(1) << 60) + INT64_C(78931732321));
 
   typedef std::pair<int32, int16> Int32Int16Pair;
   typedef std::pair<int32, int32> Int32Int32Pair;
@@ -40,7 +41,7 @@
   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));
+                   (INT64_C(1) << 60) + INT64_C(78931732321));
 
   typedef std::pair<int64, int16> Int64Int16Pair;
   typedef std::pair<int64, int32> Int64Int32Pair;
@@ -49,7 +50,7 @@
   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));
+                   (INT64_C(1) << 60) + INT64_C(78931732321));
 }
 
 // Verify that base::hash_set<const char*> compares by pointer value, not as C
diff --git a/base/containers/scoped_ptr_hash_map.h b/base/containers/scoped_ptr_hash_map.h
index 8fe550e..bc635f4 100644
--- a/base/containers/scoped_ptr_hash_map.h
+++ b/base/containers/scoped_ptr_hash_map.h
@@ -57,7 +57,7 @@
     std::pair<iterator, bool> result =
         data_.insert(std::make_pair(key, data.get()));
     if (result.second)
-      ignore_result(data.release());
+      ::ignore_result(data.release());
     return result;
   }
 
@@ -82,7 +82,7 @@
 
     ScopedPtr ret(it->second);
     it->second = NULL;
-    return ret.Pass();
+    return ret;
   }
 
   ScopedPtr take(const Key& k) {
@@ -100,7 +100,7 @@
 
     ScopedPtr ret(it->second);
     data_.erase(it);
-    return ret.Pass();
+    return ret;
   }
 
   ScopedPtr take_and_erase(const Key& k) {
diff --git a/base/containers/scoped_ptr_hash_map_unittest.cc b/base/containers/scoped_ptr_hash_map_unittest.cc
index 88fe41f..38fc91a 100644
--- a/base/containers/scoped_ptr_hash_map_unittest.cc
+++ b/base/containers/scoped_ptr_hash_map_unittest.cc
@@ -10,6 +10,15 @@
 namespace base {
 namespace {
 
+namespace namespace_with_ignore_result {
+
+class Value {};
+
+template <typename T>
+void ignore_result(const T&) {}
+
+}  // namespace namespace_with_ignore_result
+
 struct DeleteCounter {
  public:
   DeleteCounter() {}
@@ -81,5 +90,13 @@
   EXPECT_EQ(3, CountingDeleter::count());
 }
 
+// Test that using a value type from a namespace containing an ignore_result
+// function compiles correctly.
+TEST(ScopedPtrHashMapTest, IgnoreResultCompile) {
+  ScopedPtrHashMap<int, scoped_ptr<namespace_with_ignore_result::Value>>
+      scoped_map;
+  scoped_map.add(1, make_scoped_ptr(new namespace_with_ignore_result::Value));
+}
+
 }  // namespace
 }  // namespace base
diff --git a/base/containers/small_map.h b/base/containers/small_map.h
index df3d22a..8ae4219 100644
--- a/base/containers/small_map.h
+++ b/base/containers/small_map.h
@@ -187,7 +187,7 @@
   // 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);
+  static_assert(kArraySize > 0, "default initial size should be positive");
 
  public:
   typedef typename NormalMap::key_type key_type;
diff --git a/base/containers/stack_container.h b/base/containers/stack_container.h
index 54090d3..2c7dd65 100644
--- a/base/containers/stack_container.h
+++ b/base/containers/stack_container.h
@@ -57,7 +57,7 @@
     // 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);
+    static_assert(ALIGNOF(T) <= 16, "http://crbug.com/115612");
 #endif
 
     // Set when the stack buffer is used for an allocation. We do not track
diff --git a/base/cpu.cc b/base/cpu.cc
index ef3309d..ecffb86 100644
--- a/base/cpu.cc
+++ b/base/cpu.cc
@@ -43,7 +43,7 @@
     has_sse41_(false),
     has_sse42_(false),
     has_avx_(false),
-    has_avx_hardware_(false),
+    has_avx2_(false),
     has_aesni_(false),
     has_non_stop_time_stamp_counter_(false),
     has_broken_neon_(false),
@@ -72,7 +72,7 @@
 
 void __cpuid(int cpu_info[4], int info_type) {
   __asm__ volatile (
-    "cpuid \n\t"
+    "cpuid\n"
     : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
     : "a"(info_type)
   );
@@ -85,7 +85,8 @@
 uint64 _xgetbv(uint32 xcr) {
   uint32 eax, edx;
 
-  __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr));
+  __asm__ volatile (
+    "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
   return (static_cast<uint64>(edx) << 32) | eax;
 }
 
@@ -110,7 +111,7 @@
              revision = 0;
     const struct {
       const char key[17];
-      unsigned *result;
+      unsigned int* result;
     } kUnsignedValues[] = {
       {"CPU implementer", &implementer},
       {"CPU architecture", &architecture},
@@ -156,7 +157,7 @@
 
           // The string may have leading "0x" or not, so we use strtoul to
           // handle that.
-          char *endptr;
+          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) {
@@ -211,7 +212,11 @@
 
   // Interpret CPU feature information.
   if (num_ids > 0) {
+    int cpu_info7[4] = {0};
     __cpuid(cpu_info, 1);
+    if (num_ids >= 7) {
+      __cpuid(cpu_info7, 7);
+    }
     signature_ = cpu_info[0];
     stepping_ = cpu_info[0] & 0xf;
     model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
@@ -226,8 +231,6 @@
     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
@@ -239,11 +242,12 @@
     // 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] & 0x10000000) != 0 &&
         (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
         (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
         (_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
     has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
+    has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0;
   }
 
   // Get the brand string of the cpu.
@@ -275,6 +279,7 @@
 }
 
 CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
+  if (has_avx2()) return AVX2;
   if (has_avx()) return AVX;
   if (has_sse42()) return SSE42;
   if (has_sse41()) return SSE41;
diff --git a/base/cpu.h b/base/cpu.h
index 0c809f0..8c3c06c 100644
--- a/base/cpu.h
+++ b/base/cpu.h
@@ -26,6 +26,7 @@
     SSE41,
     SSE42,
     AVX,
+    AVX2,
     MAX_INTEL_MICRO_ARCHITECTURE
   };
 
@@ -46,12 +47,7 @@
   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_avx2() const { return has_avx2_; }
   bool has_aesni() const { return has_aesni_; }
   bool has_non_stop_time_stamp_counter() const {
     return has_non_stop_time_stamp_counter_;
@@ -83,7 +79,7 @@
   bool has_sse41_;
   bool has_sse42_;
   bool has_avx_;
-  bool has_avx_hardware_;
+  bool has_avx2_;
   bool has_aesni_;
   bool has_non_stop_time_stamp_counter_;
   bool has_broken_neon_;
diff --git a/base/cpu_unittest.cc b/base/cpu_unittest.cc
index 18bf959..ec14620 100644
--- a/base/cpu_unittest.cc
+++ b/base/cpu_unittest.cc
@@ -7,6 +7,11 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if _MSC_VER >= 1700
+// C4752: found Intel(R) Advanced Vector Extensions; consider using /arch:AVX.
+#pragma warning(disable: 4752)
+#endif
+
 // Tests whether we can run extended instructions represented by the CPU
 // information. This test actually executes some extended instructions (such as
 // MMX, SSE, etc.) supported by the CPU and sees we can run them without
@@ -17,57 +22,20 @@
   // 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());
+  ASSERT_TRUE(cpu.has_sse());
+  ASSERT_TRUE(cpu.has_sse2());
 
-  // 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());
-
+// GCC and clang instruction test.
+#if defined(COMPILER_GCC)
   // Execute an MMX instruction.
   __asm__ __volatile__("emms\n" : : : "mm0");
 
-  if (cpu.has_sse()) {
-    // Execute an SSE instruction.
-    __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0");
-  }
+  // 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");
-  }
+  // Execute an SSE 2 instruction.
+  __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0");
 
   if (cpu.has_sse3()) {
     // Execute an SSE 3 instruction.
@@ -88,6 +56,62 @@
     // Execute an SSE 4.2 instruction.
     __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax");
   }
-#endif
-#endif
+
+  if (cpu.has_avx()) {
+    // Execute an AVX instruction.
+    __asm__ __volatile__("vzeroupper\n" : : : "xmm0");
+  }
+
+  if (cpu.has_avx2()) {
+    // Execute an AVX 2 instruction.
+    __asm__ __volatile__("vpunpcklbw %%ymm0, %%ymm0, %%ymm0\n" : : : "xmm0");
+  }
+
+// Visual C 32 bit and ClangCL 32/64 bit test.
+#elif defined(COMPILER_MSVC) && (defined(ARCH_CPU_32_BITS) || \
+      (defined(ARCH_CPU_64_BITS) && defined(__clang__)))
+
+  // Execute an MMX instruction.
+  __asm emms;
+
+  // Execute an SSE instruction.
+  __asm xorps xmm0, xmm0;
+
+  // Execute an SSE 2 instruction.
+  __asm psrldq xmm0, 0;
+
+  if (cpu.has_sse3()) {
+    // Execute an SSE 3 instruction.
+    __asm addsubpd xmm0, xmm0;
+  }
+
+  if (cpu.has_ssse3()) {
+    // Execute a Supplimental SSE 3 instruction.
+    __asm psignb xmm0, xmm0;
+  }
+
+  if (cpu.has_sse41()) {
+    // Execute an SSE 4.1 instruction.
+    __asm pmuldq xmm0, xmm0;
+  }
+
+  if (cpu.has_sse42()) {
+    // Execute an SSE 4.2 instruction.
+    __asm crc32 eax, eax;
+  }
+
+// Visual C 2012 required for AVX.
+#if _MSC_VER >= 1700
+  if (cpu.has_avx()) {
+    // Execute an AVX instruction.
+    __asm vzeroupper;
+  }
+
+  if (cpu.has_avx2()) {
+    // Execute an AVX 2 instruction.
+    __asm vpunpcklbw ymm0, ymm0, ymm0
+  }
+#endif  // _MSC_VER >= 1700
+#endif  // defined(COMPILER_GCC)
+#endif  // defined(ARCH_CPU_X86_FAMILY)
 }
diff --git a/base/debug/BUILD.gn b/base/debug/BUILD.gn
index 8ed623b..be8084e 100644
--- a/base/debug/BUILD.gn
+++ b/base/debug/BUILD.gn
@@ -58,6 +58,7 @@
   configs += [ "//base:base_implementation" ]
 
   deps = [
+    "//base:base_static",
     "//base/memory",
     "//base/process",
   ]
diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc
index f9b4449..058b476 100644
--- a/base/debug/crash_logging.cc
+++ b/base/debug/crash_logging.cc
@@ -119,7 +119,7 @@
       hex_backtrace.push_back(s);
     }
 
-    value = JoinString(hex_backtrace, ' ');
+    value = base::JoinString(hex_backtrace, " ");
 
     // Warn if this exceeds the breakpad limits.
     DCHECK_LE(value.length(), kBreakpadValueMax);
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
index 48393f4..a2e804f 100644
--- a/base/debug/debugger_posix.cc
+++ b/base/debug/debugger_posix.cc
@@ -35,10 +35,10 @@
 #include <ostream>
 
 #include "base/basictypes.h"
+#include "base/debug/alias.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)
@@ -238,6 +238,12 @@
   // NOTE: This code MUST be async-signal safe (it's used by in-process
   // stack dumping signal handler). NO malloc or stdio is allowed here.
 
+  // Linker's ICF feature may merge this function with other functions with the
+  // same definition (e.g. any function whose sole job is to call abort()) and
+  // it may confuse the crash report processing system. http://crbug.com/508489
+  static int static_variable_to_make_this_function_unique = 0;
+  base::debug::Alias(&static_variable_to_make_this_function_unique);
+
   DEBUG_BREAK();
 #if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
   // For Android development we always build release (debug builds are
diff --git a/base/debug/gdi_debug_util_win.cc b/base/debug/gdi_debug_util_win.cc
index 3cd71f1..2db10d1 100644
--- a/base/debug/gdi_debug_util_win.cc
+++ b/base/debug/gdi_debug_util_win.cc
@@ -75,11 +75,9 @@
   base::debug::Alias(&heigth);
   base::debug::Alias(&shared_section);
 
-  int num_user_handles = GetGuiResources(GetCurrentProcess(),
-                                         GR_USEROBJECTS);
+  DWORD num_user_handles = GetGuiResources(GetCurrentProcess(), GR_USEROBJECTS);
 
-  int num_gdi_handles = GetGuiResources(GetCurrentProcess(),
-                                        GR_GDIOBJECTS);
+  DWORD 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);
diff --git a/base/debug/proc_maps_linux.cc b/base/debug/proc_maps_linux.cc
index 4c1aedf..8c8965b 100644
--- a/base/debug/proc_maps_linux.cc
+++ b/base/debug/proc_maps_linux.cc
@@ -96,8 +96,8 @@
 
   // 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);
+  std::vector<std::string> lines = SplitString(
+      input, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
 
   for (size_t i = 0; i < lines.size(); ++i) {
     // Due to splitting on '\n' the last line should be empty.
diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc
index ed553cd..924c769 100644
--- a/base/debug/profiler.cc
+++ b/base/debug/profiler.cc
@@ -7,8 +7,8 @@
 #include <string>
 
 #include "base/process/process_handle.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
 
 #if defined(OS_WIN)
 #include "base/win/pe_image.h"
@@ -30,8 +30,8 @@
 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);
+  std::string pid = IntToString(GetCurrentProcId());
+  std::string count = IntToString(profile_count);
   ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
   ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
   ProfilerStart(full_name.c_str());
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
index fb271b6..d35468f 100644
--- a/base/debug/stack_trace.h
+++ b/base/debug/stack_trace.h
@@ -26,16 +26,13 @@
 // 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.
+// In sandboxed processes, this has to be called before the sandbox is turned
+// on.
 // Calling this function on Linux opens /proc/self/maps and caches its
-// contents. In DEBUG builds, this function also opens the object files that
-// are loaded in memory and caches their file descriptors (this cannot be
+// contents. In non-official builds, this function also opens the object files
+// that are loaded in memory and caches their file descriptors (this cannot be
 // done in official builds because it has security implications).
-BASE_EXPORT bool EnableInProcessStackDumpingForSandbox();
+BASE_EXPORT bool EnableInProcessStackDumping();
 
 // A stacktrace can be helpful in debugging. For example, you can include a
 // stacktrace member in a object (probably around #ifndef NDEBUG) so that you
@@ -54,7 +51,7 @@
   // 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(_EXCEPTION_POINTERS* exception_pointers);
   StackTrace(const _CONTEXT* context);
 #endif
 
@@ -79,7 +76,7 @@
 
  private:
 #if defined(OS_WIN)
-  void InitTrace(_CONTEXT* context_record);
+  void InitTrace(const _CONTEXT* context_record);
 #endif
 
   // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
index 2eac14e..c49a762 100644
--- a/base/debug/stack_trace_posix.cc
+++ b/base/debug/stack_trace_posix.cc
@@ -281,6 +281,16 @@
   }
   PrintToStderr("\n");
 
+#if defined(CFI_ENFORCEMENT)
+  if (signal == SIGILL && info->si_code == ILL_ILLOPN) {
+    PrintToStderr(
+        "CFI: Most likely a control flow integrity violation; for more "
+        "information see:\n");
+    PrintToStderr(
+        "https://www.chromium.org/developers/testing/control-flow-integrity\n");
+  }
+#endif
+
   debug::StackTrace().Print();
 
 #if defined(OS_LINUX)
@@ -334,7 +344,7 @@
     { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
     { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
     { " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
-#endif
+#endif  // ARCH_CPU_32_BITS
   };
 
 #if ARCH_CPU_32_BITS
@@ -353,49 +363,20 @@
       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;
+#endif  // ARCH_CPU_X86_FAMILY
+#endif  // defined(OS_LINUX)
 
-  // 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));
+  PrintToStderr("[end of stack trace]\n");
 
-  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)
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  if (::signal(signal, SIG_DFL) == SIG_ERR)
+    _exit(1);
+#else
+  // Non-Mac OSes should probably reraise the signal as well, but the Linux
+  // sandbox tests break on CrOS devices.
+  // https://code.google.com/p/chromium/issues/detail?id=551681
   _exit(1);
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 }
 
 class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
@@ -492,14 +473,14 @@
   }
 
   // Returns a O_RDONLY file descriptor for |file_path| if it was opened
-  // sucessfully during the initialization.  The file is repositioned at
+  // successfully during the initialization.  The file is repositioned at
   // offset 0.
   // IMPORTANT: This function must be async-signal-safe because it can be
   // called from a signal handler (symbolizing stack frames for a crash).
   int GetFileDescriptor(const char* file_path) {
     int fd = -1;
 
-#if !defined(NDEBUG)
+#if !defined(OFFICIAL_BUILD)
     if (file_path) {
       // The assumption here is that iterating over std::map<std::string, int>
       // using a const_iterator does not allocate dynamic memory, hense it is
@@ -520,7 +501,7 @@
         fd = -1;
       }
     }
-#endif  // !defined(NDEBUG)
+#endif  // !defined(OFFICIAL_BUILD)
 
     return fd;
   }
@@ -606,11 +587,9 @@
   // 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)
+    // not safe for production builds.  Hence it is only done in non-official
+    // builds.  For more details, take a look at: http://crbug.com/341966.
+#if !defined(OFFICIAL_BUILD)
     // Open the object files for all read-only executable regions and cache
     // their file descriptors.
     std::vector<MappedMemoryRegion>::const_iterator it;
@@ -642,7 +621,7 @@
         }
       }
     }
-#endif  // !defined(NDEBUG)
+#endif  // !defined(OFFICIAL_BUILD)
   }
 
   // Initializes and installs the symbolization callback.
@@ -664,7 +643,7 @@
 
   // Closes all file descriptors owned by this instance.
   void CloseObjectFiles() {
-#if !defined(NDEBUG)
+#if !defined(OFFICIAL_BUILD)
     std::map<std::string, int>::iterator it;
     for (it = modules_.begin(); it != modules_.end(); ++it) {
       int ret = IGNORE_EINTR(close(it->second));
@@ -672,19 +651,18 @@
       it->second = -1;
     }
     modules_.clear();
-#endif  // !defined(NDEBUG)
+#endif  // !defined(OFFICIAL_BUILD)
   }
 
   // Set to true upon successful initialization.
   bool is_initialized_;
 
-#if !defined(NDEBUG)
+#if !defined(OFFICIAL_BUILD)
   // Mapping from file name to file descriptor.  Includes file descriptors
   // for all successfully opened object files and the file descriptor for
-  // /proc/self/maps.  This code is not safe for release builds so
-  // this is only done for DEBUG builds.
+  // /proc/self/maps.  This code is not safe for production builds.
   std::map<std::string, int> modules_;
-#endif  // !defined(NDEBUG)
+#endif  // !defined(OFFICIAL_BUILD)
 
   // Cache for the process memory regions.  Produced by parsing the contents
   // of /proc/self/maps cache.
@@ -694,15 +672,11 @@
 };
 #endif  // USE_SYMBOLIZE
 
-bool EnableInProcessStackDumpingForSandbox() {
+bool EnableInProcessStackDumping() {
 #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.
@@ -767,7 +741,7 @@
 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) {
+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)
@@ -778,13 +752,14 @@
     return NULL;
   }
 
-  char *start = buf;
+  char* start = buf;
 
   uintptr_t j = i;
 
   // Handle negative numbers (only for base 10).
   if (i < 0 && base == 10) {
-    j = -i;
+    // This does "j = -i" while avoiding integer overflow.
+    j = static_cast<uintptr_t>(-(i + 1)) + 1;
 
     // Make sure we can write the '-' character.
     if (++n > sz) {
@@ -796,7 +771,7 @@
 
   // Loop until we have converted the entire number. Output at least one
   // character (i.e. '0').
-  char *ptr = start;
+  char* ptr = start;
   do {
     // Make sure there is still enough space left in our output buffer.
     if (++n > sz) {
diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc
index 15c9093..804587e 100644
--- a/base/debug/stack_trace_unittest.cc
+++ b/base/debug/stack_trace_unittest.cc
@@ -135,8 +135,14 @@
 
 #if defined(OS_POSIX) && !defined(OS_ANDROID)
 #if !defined(OS_IOS)
+static char* newArray() {
+  // Clang warns about the mismatched new[]/delete if they occur in the same
+  // function.
+  return new char[10];
+}
+
 MULTIPROCESS_TEST_MAIN(MismatchedMallocChildProcess) {
-  char* pointer = new char[10];
+  char* pointer = newArray();
   delete pointer;
   return 2;
 }
diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc
index 55d5562..2679077 100644
--- a/base/debug/stack_trace_win.cc
+++ b/base/debug/stack_trace_win.cc
@@ -26,6 +26,9 @@
 // exception. Only used in unit tests.
 LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
 
+bool g_initialized_symbols = false;
+DWORD g_init_error = ERROR_SUCCESS;
+
 // Prints the exception call stack.
 // This is the unit tests exception filter.
 long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
@@ -42,6 +45,55 @@
   return FilePath(system_buffer);
 }
 
+bool InitializeSymbols() {
+  if (g_initialized_symbols)
+    return g_init_error == ERROR_SUCCESS;
+  g_initialized_symbols = true;
+  // 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)) {
+    g_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: " << g_init_error;
+    return false;
+  }
+
+  // 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)) {
+    g_init_error = GetLastError();
+    DLOG(WARNING) << "SymGetSearchPath failed: " << g_init_error;
+    return false;
+  }
+
+  std::wstring new_path(std::wstring(symbols_path.get()) +
+                        L";" + GetExePath().DirName().value());
+  if (!SymSetSearchPathW(GetCurrentProcess(), new_path.c_str())) {
+    g_init_error = GetLastError();
+    DLOG(WARNING) << "SymSetSearchPath failed." << g_init_error;
+    return false;
+  }
+
+  g_init_error = ERROR_SUCCESS;
+  return true;
+}
+
 // 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
@@ -66,11 +118,6 @@
       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:
   //
@@ -132,51 +179,10 @@
  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;
-    }
+  SymbolContext() {
+    InitializeSymbols();
   }
 
-  DWORD init_error_;
   base::Lock lock_;
   DISALLOW_COPY_AND_ASSIGN(SymbolContext);
 };
@@ -187,8 +193,11 @@
   // 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;
+
+  // Need to initialize symbols early in the process or else this fails on
+  // swarming (since symbols are in different directory than in the exes) and
+  // also release x64.
+  return InitializeSymbols();
 }
 
 // Disable optimizations for the StackTrace::StackTrace function. It is
@@ -209,21 +218,23 @@
 #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(EXCEPTION_POINTERS* exception_pointers) {
+  InitTrace(exception_pointers->ContextRecord);
 }
 
 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);
+  InitTrace(context);
 }
 
-void StackTrace::InitTrace(CONTEXT* context_record) {
+void StackTrace::InitTrace(const CONTEXT* context_record) {
+  // StackWalk64 modifies the register context in place, so we have to copy it
+  // so that downstream exception handlers get the right context.  The incoming
+  // context may have had more register state (YMM, etc) than we need to unwind
+  // the stack. Typically StackWalk64 only needs integer and control registers.
+  CONTEXT context_copy;
+  memcpy(&context_copy, context_record, sizeof(context_copy));
+  context_copy.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
+
   // When walking an exception stack, we need to use StackWalk64().
   count_ = 0;
   // Initialize stack walking.
@@ -247,7 +258,7 @@
                      GetCurrentProcess(),
                      GetCurrentThread(),
                      &stack_frame,
-                     context_record,
+                     &context_copy,
                      NULL,
                      &SymFunctionTableAccess64,
                      &SymGetModuleBase64,
@@ -266,9 +277,8 @@
 
 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
+  if (g_init_error != ERROR_SUCCESS) {
+    (*os) << "Error initializing symbols (" << g_init_error
           << ").  Dumping unresolved backtrace:\n";
     for (size_t i = 0; (i < count_) && os->good(); ++i) {
       (*os) << "\t" << trace_[i] << "\n";
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc
index 19df8cb..e47a043 100644
--- a/base/debug/task_annotator.cc
+++ b/base/debug/task_annotator.cc
@@ -20,36 +20,25 @@
 
 void TaskAnnotator::DidQueueTask(const char* queue_function,
                                  const PendingTask& pending_task) {
-  TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+  TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
                           queue_function,
-                          TRACE_ID_MANGLE(GetTaskTraceID(pending_task)));
+                          TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
+                          TRACE_EVENT_FLAG_FLOW_OUT);
 }
 
 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());
+  TRACE_EVENT_WITH_FLOW1(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+                          queue_function,
+                          TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
+                          TRACE_EVENT_FLAG_FLOW_IN,
+                          "queue_duration",
+                          queue_duration.InMilliseconds());
 
   // Before running the task, store the program counter where it was posted
   // and deliberately alias it to ensure it is on the stack if the task
diff --git a/base/debug/task_annotator.h b/base/debug/task_annotator.h
index aa5f17b..b5cf6c2 100644
--- a/base/debug/task_annotator.h
+++ b/base/debug/task_annotator.h
@@ -25,11 +25,8 @@
                     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);
+  // passed into |DidQueueTask| for this task.
+  void RunTask(const char* queue_function, const PendingTask& pending_task);
 
  private:
   // Creates a process-wide unique ID to represent this task in trace events.
@@ -40,6 +37,11 @@
   DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
 };
 
+#define TRACE_TASK_EXECUTION(run_function, task)           \
+  TRACE_EVENT2("toplevel", (run_function), "src_file",     \
+               (task).posted_from.file_name(), "src_func", \
+               (task).posted_from.function_name());
+
 }  // namespace debug
 }  // namespace base
 
diff --git a/base/debug/task_annotator_unittest.cc b/base/debug/task_annotator_unittest.cc
index ddffc21..9f5c442 100644
--- a/base/debug/task_annotator_unittest.cc
+++ b/base/debug/task_annotator_unittest.cc
@@ -24,8 +24,7 @@
   TaskAnnotator annotator;
   annotator.DidQueueTask("TaskAnnotatorTest::Queue", pending_task);
   EXPECT_EQ(0, result);
-  annotator.RunTask(
-      "TaskAnnotatorTest::Queue", "TaskAnnotatorTest::Run", pending_task);
+  annotator.RunTask("TaskAnnotatorTest::Queue", pending_task);
   EXPECT_EQ(123, result);
 }
 
diff --git a/base/debug_message.cc b/base/debug_message.cc
deleted file mode 100644
index 10f441d..0000000
--- a/base/debug_message.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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/environment.cc b/base/environment.cc
index 6cf7a18..ca24ac7 100644
--- a/base/environment.cc
+++ b/base/environment.cc
@@ -20,7 +20,7 @@
 
 namespace {
 
-class EnvironmentImpl : public base::Environment {
+class EnvironmentImpl : public Environment {
  public:
   bool GetVar(const char* variable_name, std::string* result) override {
     if (GetVarImpl(variable_name, result))
@@ -33,9 +33,9 @@
     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));
+      alternate_case_var = ToUpperASCII(variable_name);
     else if (first_char >= 'A' && first_char <= 'Z')
-      alternate_case_var = base::StringToLowerASCII(std::string(variable_name));
+      alternate_case_var = ToLowerASCII(variable_name);
     else
       return false;
     return GetVarImpl(alternate_case_var.c_str(), result);
@@ -228,7 +228,7 @@
     result[i] = &storage_data[result_indices[i]];
   result[result_indices.size()] = 0;  // Null terminator.
 
-  return result.Pass();
+  return result;
 }
 
 #endif  // OS_POSIX
diff --git a/base/environment_unittest.cc b/base/environment_unittest.cc
index f0577a8..c955e79 100644
--- a/base/environment_unittest.cc
+++ b/base/environment_unittest.cc
@@ -129,7 +129,7 @@
   EnvironmentMap changes;
   scoped_ptr<char*[]> e;
 
-  e = AlterEnvironment(empty, changes).Pass();
+  e = AlterEnvironment(empty, changes);
   EXPECT_TRUE(e[0] == NULL);
 
   changes["A"] = "1";
diff --git a/base/feature_list.cc b/base/feature_list.cc
new file mode 100644
index 0000000..104bf08
--- /dev/null
+++ b/base/feature_list.cc
@@ -0,0 +1,238 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/feature_list.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+namespace {
+
+// Pointer to the FeatureList instance singleton that was set via
+// FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to
+// have more control over initialization timing. Leaky.
+FeatureList* g_instance = nullptr;
+
+// Some characters are not allowed to appear in feature names or the associated
+// field trial names, as they are used as special characters for command-line
+// serialization. This function checks that the strings are ASCII (since they
+// are used in command-line API functions that require ASCII) and whether there
+// are any reserved characters present, returning true if the string is valid.
+// Only called in DCHECKs.
+bool IsValidFeatureOrFieldTrialName(const std::string& name) {
+  return IsStringASCII(name) && name.find_first_of(",<") == std::string::npos;
+}
+
+}  // namespace
+
+FeatureList::FeatureList() : initialized_(false) {}
+
+FeatureList::~FeatureList() {}
+
+void FeatureList::InitializeFromCommandLine(
+    const std::string& enable_features,
+    const std::string& disable_features) {
+  DCHECK(!initialized_);
+
+  // Process disabled features first, so that disabled ones take precedence over
+  // enabled ones (since RegisterOverride() uses insert()).
+  RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
+  RegisterOverridesFromCommandLine(enable_features, OVERRIDE_ENABLE_FEATURE);
+}
+
+bool FeatureList::IsFeatureOverriddenFromCommandLine(
+    const std::string& feature_name,
+    OverrideState state) const {
+  auto it = overrides_.find(feature_name);
+  return it != overrides_.end() && it->second.overridden_state == state &&
+         !it->second.overridden_by_field_trial;
+}
+
+void FeatureList::AssociateReportingFieldTrial(
+    const std::string& feature_name,
+    OverrideState for_overridden_state,
+    FieldTrial* field_trial) {
+  DCHECK(
+      IsFeatureOverriddenFromCommandLine(feature_name, for_overridden_state));
+
+  // Only one associated field trial is supported per feature. This is generally
+  // enforced server-side.
+  OverrideEntry* entry = &overrides_.find(feature_name)->second;
+  if (entry->field_trial) {
+    NOTREACHED() << "Feature " << feature_name
+                 << " already has trial: " << entry->field_trial->trial_name()
+                 << ", associating trial: " << field_trial->trial_name();
+    return;
+  }
+
+  entry->field_trial = field_trial;
+}
+
+void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
+                                             OverrideState override_state,
+                                             FieldTrial* field_trial) {
+  DCHECK(field_trial);
+  DCHECK(!ContainsKey(overrides_, feature_name) ||
+         !overrides_.find(feature_name)->second.field_trial)
+      << "Feature " << feature_name
+      << " has conflicting field trial overrides: "
+      << overrides_.find(feature_name)->second.field_trial->trial_name()
+      << " / " << field_trial->trial_name();
+
+  RegisterOverride(feature_name, override_state, field_trial);
+}
+
+void FeatureList::GetFeatureOverrides(std::string* enable_overrides,
+                                      std::string* disable_overrides) {
+  DCHECK(initialized_);
+
+  enable_overrides->clear();
+  disable_overrides->clear();
+
+  for (const auto& entry : overrides_) {
+    std::string* target_list = nullptr;
+    switch (entry.second.overridden_state) {
+      case OVERRIDE_ENABLE_FEATURE:
+        target_list = enable_overrides;
+        break;
+      case OVERRIDE_DISABLE_FEATURE:
+        target_list = disable_overrides;
+        break;
+    }
+
+    if (!target_list->empty())
+      target_list->push_back(',');
+    target_list->append(entry.first);
+    if (entry.second.field_trial) {
+      target_list->push_back('<');
+      target_list->append(entry.second.field_trial->trial_name());
+    }
+  }
+}
+
+// static
+bool FeatureList::IsEnabled(const Feature& feature) {
+  return GetInstance()->IsFeatureEnabled(feature);
+}
+
+// static
+std::vector<std::string> FeatureList::SplitFeatureListString(
+    const std::string& input) {
+  return SplitString(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+}
+
+// static
+void FeatureList::InitializeInstance() {
+  if (g_instance)
+    return;
+  SetInstance(make_scoped_ptr(new FeatureList));
+}
+
+// static
+FeatureList* FeatureList::GetInstance() {
+  return g_instance;
+}
+
+// static
+void FeatureList::SetInstance(scoped_ptr<FeatureList> instance) {
+  DCHECK(!g_instance);
+  instance->FinalizeInitialization();
+
+  // Note: Intentional leak of global singleton.
+  g_instance = instance.release();
+}
+
+// static
+void FeatureList::ClearInstanceForTesting() {
+  delete g_instance;
+  g_instance = nullptr;
+}
+
+void FeatureList::FinalizeInitialization() {
+  DCHECK(!initialized_);
+  initialized_ = true;
+}
+
+bool FeatureList::IsFeatureEnabled(const Feature& feature) {
+  DCHECK(initialized_);
+  DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
+  DCHECK(CheckFeatureIdentity(feature)) << feature.name;
+
+  auto it = overrides_.find(feature.name);
+  if (it != overrides_.end()) {
+    const OverrideEntry& entry = it->second;
+
+    // Activate the corresponding field trial, if necessary.
+    if (entry.field_trial)
+      entry.field_trial->group();
+
+    // TODO(asvitkine) Expand this section as more support is added.
+    return entry.overridden_state == OVERRIDE_ENABLE_FEATURE;
+  }
+  // Otherwise, return the default state.
+  return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
+}
+
+void FeatureList::RegisterOverridesFromCommandLine(
+    const std::string& feature_list,
+    OverrideState overridden_state) {
+  for (const auto& value : SplitFeatureListString(feature_list)) {
+    StringPiece feature_name(value);
+    base::FieldTrial* trial = nullptr;
+
+    // The entry may be of the form FeatureName<FieldTrialName - in which case,
+    // this splits off the field trial name and associates it with the override.
+    std::string::size_type pos = feature_name.find('<');
+    if (pos != std::string::npos) {
+      feature_name.set(value.data(), pos);
+      trial = base::FieldTrialList::Find(value.substr(pos + 1));
+    }
+
+    RegisterOverride(feature_name, overridden_state, trial);
+  }
+}
+
+void FeatureList::RegisterOverride(StringPiece feature_name,
+                                   OverrideState overridden_state,
+                                   FieldTrial* field_trial) {
+  DCHECK(!initialized_);
+  if (field_trial) {
+    DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name()))
+        << field_trial->trial_name();
+  }
+
+  // Note: The semantics of insert() is that it does not overwrite the entry if
+  // one already exists for the key. Thus, only the first override for a given
+  // feature name takes effect.
+  overrides_.insert(std::make_pair(
+      feature_name.as_string(), OverrideEntry(overridden_state, field_trial)));
+}
+
+bool FeatureList::CheckFeatureIdentity(const Feature& feature) {
+  AutoLock auto_lock(feature_identity_tracker_lock_);
+
+  auto it = feature_identity_tracker_.find(feature.name);
+  if (it == feature_identity_tracker_.end()) {
+    // If it's not tracked yet, register it.
+    feature_identity_tracker_[feature.name] = &feature;
+    return true;
+  }
+  // Compare address of |feature| to the existing tracked entry.
+  return it->second == &feature;
+}
+
+FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state,
+                                          FieldTrial* field_trial)
+    : overridden_state(overridden_state),
+      field_trial(field_trial),
+      overridden_by_field_trial(field_trial != nullptr) {}
+
+}  // namespace base
diff --git a/base/feature_list.h b/base/feature_list.h
new file mode 100644
index 0000000..3967263
--- /dev/null
+++ b/base/feature_list.h
@@ -0,0 +1,238 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FEATURE_LIST_H_
+#define BASE_FEATURE_LIST_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class FieldTrial;
+
+// Specifies whether a given feature is enabled or disabled by default.
+enum FeatureState {
+  FEATURE_DISABLED_BY_DEFAULT,
+  FEATURE_ENABLED_BY_DEFAULT,
+};
+
+// The Feature struct is used to define the default state for a feature. See
+// comment below for more details. There must only ever be one struct instance
+// for a given feature name - generally defined as a constant global variable or
+// file static.
+struct BASE_EXPORT Feature {
+  // The name of the feature. This should be unique to each feature and is used
+  // for enabling/disabling features via command line flags and experiments.
+  const char* const name;
+
+  // The default state (i.e. enabled or disabled) for this feature.
+  const FeatureState default_state;
+};
+
+// The FeatureList class is used to determine whether a given feature is on or
+// off. It provides an authoritative answer, taking into account command-line
+// overrides and experimental control.
+//
+// The basic use case is for any feature that can be toggled (e.g. through
+// command-line or an experiment) to have a defined Feature struct, e.g.:
+//
+//   const base::Feature kMyGreatFeature {
+//     "MyGreatFeature", base::FEATURE_ENABLED_BY_DEFAULT
+//   };
+//
+// Then, client code that wishes to query the state of the feature would check:
+//
+//   if (base::FeatureList::IsEnabled(kMyGreatFeature)) {
+//     // Feature code goes here.
+//   }
+//
+// Behind the scenes, the above call would take into account any command-line
+// flags to enable or disable the feature, any experiments that may control it
+// and finally its default state (in that order of priority), to determine
+// whether the feature is on.
+//
+// Features can be explicitly forced on or off by specifying a list of comma-
+// separated feature names via the following command-line flags:
+//
+//   --enable-features=Feature5,Feature7
+//   --disable-features=Feature1,Feature2,Feature3
+//
+// After initialization (which should be done single-threaded), the FeatureList
+// API is thread safe.
+//
+// Note: This class is a singleton, but does not use base/memory/singleton.h in
+// order to have control over its initialization sequence. Specifically, the
+// intended use is to create an instance of this class and fully initialize it,
+// before setting it as the singleton for a process, via SetInstance().
+class BASE_EXPORT FeatureList {
+ public:
+  FeatureList();
+  ~FeatureList();
+
+  // Initializes feature overrides via command-line flags |enable_features| and
+  // |disable_features|, each of which is a comma-separated list of features to
+  // enable or disable, respectively. If a feature appears on both lists, then
+  // it will be disabled. If a list entry has the format "FeatureName<TrialName"
+  // then this initialization will also associate the feature state override
+  // with the named field trial, if it exists. Must only be invoked during the
+  // initialization phase (before FinalizeInitialization() has been called).
+  void InitializeFromCommandLine(const std::string& enable_features,
+                                 const std::string& disable_features);
+
+  // Specifies whether a feature override enables or disables the feature.
+  enum OverrideState {
+    OVERRIDE_DISABLE_FEATURE,
+    OVERRIDE_ENABLE_FEATURE,
+  };
+
+  // Returns true if the state of |feature_name| has been overridden via
+  // |InitializeFromCommandLine()|.
+  bool IsFeatureOverriddenFromCommandLine(const std::string& feature_name,
+                                          OverrideState state) const;
+
+  // Associates a field trial for reporting purposes corresponding to the
+  // command-line setting the feature state to |for_overridden_state|. The trial
+  // will be activated when the state of the feature is first queried. This
+  // should be called during registration, after InitializeFromCommandLine() has
+  // been called but before the instance is registered via SetInstance().
+  void AssociateReportingFieldTrial(const std::string& feature_name,
+                                    OverrideState for_overridden_state,
+                                    FieldTrial* field_trial);
+
+  // Registers a field trial to override the enabled state of the specified
+  // feature to |override_state|. Command-line overrides still take precedence
+  // over field trials, so this will have no effect if the feature is being
+  // overridden from the command-line. The associated field trial will be
+  // activated when the feature state for this feature is queried. This should
+  // be called during registration, after InitializeFromCommandLine() has been
+  // called but before the instance is registered via SetInstance().
+  void RegisterFieldTrialOverride(const std::string& feature_name,
+                                  OverrideState override_state,
+                                  FieldTrial* field_trial);
+
+  // Returns comma-separated lists of feature names (in the same format that is
+  // accepted by InitializeFromCommandLine()) corresponding to features that
+  // have been overridden - either through command-line or via FieldTrials. For
+  // those features that have an associated FieldTrial, the output entry will be
+  // of the format "FeatureName<TrialName", where "TrialName" is the name of the
+  // FieldTrial. Must be called only after the instance has been initialized and
+  // registered.
+  void GetFeatureOverrides(std::string* enable_overrides,
+                           std::string* disable_overrides);
+
+  // Returns whether the given |feature| is enabled. Must only be called after
+  // the singleton instance has been registered via SetInstance(). Additionally,
+  // a feature with a given name must only have a single corresponding Feature
+  // struct, which is checked in builds with DCHECKs enabled.
+  static bool IsEnabled(const Feature& feature);
+
+  // Splits a comma-separated string containing feature names into a vector.
+  static std::vector<std::string> SplitFeatureListString(
+      const std::string& input);
+
+  // Initializes and sets a default instance of FeatureList if one has not yet
+  // already been set. No-op otherwise.
+  static void InitializeInstance();
+
+  // Returns the singleton instance of FeatureList. Will return null until an
+  // instance is registered via SetInstance().
+  static FeatureList* GetInstance();
+
+  // Registers the given |instance| to be the singleton feature list for this
+  // process. This should only be called once and |instance| must not be null.
+  static void SetInstance(scoped_ptr<FeatureList> instance);
+
+  // Clears the previously-registered singleton instance for tests.
+  static void ClearInstanceForTesting();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity);
+
+  struct OverrideEntry {
+    // The overridden enable (on/off) state of the feature.
+    const OverrideState overridden_state;
+
+    // An optional associated field trial, which will be activated when the
+    // state of the feature is queried for the first time. Weak pointer to the
+    // FieldTrial object that is owned by the FieldTrialList singleton.
+    base::FieldTrial* field_trial;
+
+    // Specifies whether the feature's state is overridden by |field_trial|.
+    // If it's not, and |field_trial| is not null, it means it is simply an
+    // associated field trial for reporting purposes (and |overridden_state|
+    // came from the command-line).
+    const bool overridden_by_field_trial;
+
+    // TODO(asvitkine): Expand this as more support is added.
+
+    // Constructs an OverrideEntry for the given |overridden_state|. If
+    // |field_trial| is not null, it implies that |overridden_state| comes from
+    // the trial, so |overridden_by_field_trial| will be set to true.
+    OverrideEntry(OverrideState overridden_state, FieldTrial* field_trial);
+  };
+
+  // Finalizes the initialization state of the FeatureList, so that no further
+  // overrides can be registered. This is called by SetInstance() on the
+  // singleton feature list that is being registered.
+  void FinalizeInitialization();
+
+  // Returns whether the given |feature| is enabled. This is invoked by the
+  // public FeatureList::IsEnabled() static function on the global singleton.
+  // Requires the FeatureList to have already been fully initialized.
+  bool IsFeatureEnabled(const Feature& feature);
+
+  // For each feature name in comma-separated list of strings |feature_list|,
+  // registers an override with the specified |overridden_state|. Also, will
+  // associate an optional named field trial if the entry is of the format
+  // "FeatureName<TrialName".
+  void RegisterOverridesFromCommandLine(const std::string& feature_list,
+                                        OverrideState overridden_state);
+
+  // Registers an override for feature |feature_name|. The override specifies
+  // whether the feature should be on or off (via |overridden_state|), which
+  // will take precedence over the feature's default state. If |field_trial| is
+  // not null, registers the specified field trial object to be associated with
+  // the feature, which will activate the field trial when the feature state is
+  // queried. If an override is already registered for the given feature, it
+  // will not be changed.
+  void RegisterOverride(StringPiece feature_name,
+                        OverrideState overridden_state,
+                        FieldTrial* field_trial);
+
+  // Verifies that there's only a single definition of a Feature struct for a
+  // given feature name. Keeps track of the first seen Feature struct for each
+  // feature. Returns false when called on a Feature struct with a different
+  // address than the first one it saw for that feature name. Used only from
+  // DCHECKs and tests.
+  bool CheckFeatureIdentity(const Feature& feature);
+
+  // Map from feature name to an OverrideEntry struct for the feature, if it
+  // exists.
+  std::map<std::string, OverrideEntry> overrides_;
+
+  // Locked map that keeps track of seen features, to ensure a single feature is
+  // only defined once. This verification is only done in builds with DCHECKs
+  // enabled.
+  Lock feature_identity_tracker_lock_;
+  std::map<std::string, const Feature*> feature_identity_tracker_;
+
+  // Whether this object has been fully initialized. This gets set to true as a
+  // result of FinalizeInitialization().
+  bool initialized_;
+
+  DISALLOW_COPY_AND_ASSIGN(FeatureList);
+};
+
+}  // namespace base
+
+#endif  // BASE_FEATURE_LIST_H_
diff --git a/base/feature_list_unittest.cc b/base/feature_list_unittest.cc
new file mode 100644
index 0000000..29c1f16
--- /dev/null
+++ b/base/feature_list_unittest.cc
@@ -0,0 +1,355 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/feature_list.h"
+
+#include <utility>
+
+#include "base/format_macros.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const char kFeatureOnByDefaultName[] = "OnByDefault";
+struct Feature kFeatureOnByDefault {
+  kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
+};
+
+const char kFeatureOffByDefaultName[] = "OffByDefault";
+struct Feature kFeatureOffByDefault {
+  kFeatureOffByDefaultName, FEATURE_DISABLED_BY_DEFAULT
+};
+
+std::string SortFeatureListString(const std::string& feature_list) {
+  std::vector<std::string> features =
+      FeatureList::SplitFeatureListString(feature_list);
+  std::sort(features.begin(), features.end());
+  return JoinString(features, ",");
+}
+
+}  // namespace
+
+class FeatureListTest : public testing::Test {
+ public:
+  FeatureListTest() : feature_list_(nullptr) {
+    RegisterFeatureListInstance(make_scoped_ptr(new FeatureList));
+  }
+  ~FeatureListTest() override { ClearFeatureListInstance(); }
+
+  void RegisterFeatureListInstance(scoped_ptr<FeatureList> feature_list) {
+    FeatureList::ClearInstanceForTesting();
+    feature_list_ = feature_list.get();
+    FeatureList::SetInstance(std::move(feature_list));
+  }
+  void ClearFeatureListInstance() {
+    FeatureList::ClearInstanceForTesting();
+    feature_list_ = nullptr;
+  }
+
+  FeatureList* feature_list() { return feature_list_; }
+
+ private:
+  // Weak. Owned by the FeatureList::SetInstance().
+  FeatureList* feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(FeatureListTest);
+};
+
+TEST_F(FeatureListTest, DefaultStates) {
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+}
+
+TEST_F(FeatureListTest, InitializeFromCommandLine) {
+  struct {
+    const char* enable_features;
+    const char* disable_features;
+    bool expected_feature_on_state;
+    bool expected_feature_off_state;
+  } test_cases[] = {
+      {"", "", true, false},
+      {"OffByDefault", "", true, true},
+      {"OffByDefault", "OnByDefault", false, true},
+      {"OnByDefault,OffByDefault", "", true, true},
+      {"", "OnByDefault,OffByDefault", false, false},
+      // In the case an entry is both, disable takes precedence.
+      {"OnByDefault", "OnByDefault,OffByDefault", false, false},
+  };
+
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    const auto& test_case = test_cases[i];
+    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
+                                    test_case.enable_features,
+                                    test_case.disable_features));
+
+    ClearFeatureListInstance();
+    scoped_ptr<FeatureList> feature_list(new FeatureList);
+    feature_list->InitializeFromCommandLine(test_case.enable_features,
+                                            test_case.disable_features);
+    RegisterFeatureListInstance(std::move(feature_list));
+
+    EXPECT_EQ(test_case.expected_feature_on_state,
+              FeatureList::IsEnabled(kFeatureOnByDefault))
+        << i;
+    EXPECT_EQ(test_case.expected_feature_off_state,
+              FeatureList::IsEnabled(kFeatureOffByDefault))
+        << i;
+  }
+}
+
+TEST_F(FeatureListTest, CheckFeatureIdentity) {
+  // Tests that CheckFeatureIdentity() correctly detects when two different
+  // structs with the same feature name are passed to it.
+
+  // Call it twice for each feature at the top of the file, since the first call
+  // makes it remember the entry and the second call will verify it.
+  EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault));
+  EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault));
+  EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault));
+  EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault));
+
+  // Now, call it with a distinct struct for |kFeatureOnByDefaultName|, which
+  // should return false.
+  struct Feature kFeatureOnByDefault2 {
+    kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
+  };
+  EXPECT_FALSE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault2));
+}
+
+TEST_F(FeatureListTest, FieldTrialOverrides) {
+  struct {
+    FeatureList::OverrideState trial1_state;
+    FeatureList::OverrideState trial2_state;
+  } test_cases[] = {
+      {FeatureList::OVERRIDE_DISABLE_FEATURE,
+       FeatureList::OVERRIDE_DISABLE_FEATURE},
+      {FeatureList::OVERRIDE_DISABLE_FEATURE,
+       FeatureList::OVERRIDE_ENABLE_FEATURE},
+      {FeatureList::OVERRIDE_ENABLE_FEATURE,
+       FeatureList::OVERRIDE_DISABLE_FEATURE},
+      {FeatureList::OVERRIDE_ENABLE_FEATURE,
+       FeatureList::OVERRIDE_ENABLE_FEATURE},
+  };
+
+  FieldTrial::ActiveGroup active_group;
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    const auto& test_case = test_cases[i];
+    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
+
+    ClearFeatureListInstance();
+
+    FieldTrialList field_trial_list(nullptr);
+    scoped_ptr<FeatureList> feature_list(new FeatureList);
+
+    FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
+    FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
+    feature_list->RegisterFieldTrialOverride(kFeatureOnByDefaultName,
+                                             test_case.trial1_state, trial1);
+    feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
+                                             test_case.trial2_state, trial2);
+    RegisterFeatureListInstance(std::move(feature_list));
+
+    // Initially, neither trial should be active.
+    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
+    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
+
+    const bool expected_enabled_1 =
+        (test_case.trial1_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
+    EXPECT_EQ(expected_enabled_1, FeatureList::IsEnabled(kFeatureOnByDefault));
+    // The above should have activated |trial1|.
+    EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
+    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
+
+    const bool expected_enabled_2 =
+        (test_case.trial2_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
+    EXPECT_EQ(expected_enabled_2, FeatureList::IsEnabled(kFeatureOffByDefault));
+    // The above should have activated |trial2|.
+    EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
+    EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
+  }
+}
+
+TEST_F(FeatureListTest, CommandLineTakesPrecedenceOverFieldTrial) {
+  ClearFeatureListInstance();
+
+  FieldTrialList field_trial_list(nullptr);
+  scoped_ptr<FeatureList> feature_list(new FeatureList);
+
+  // The feature is explicitly enabled on the command-line.
+  feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
+
+  // But the FieldTrial would set the feature to disabled.
+  FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
+  feature_list->RegisterFieldTrialOverride(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
+  // Command-line should take precedence.
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
+  // Since the feature is on due to the command-line, and not as a result of the
+  // field trial, the field trial should not be activated (since the Associate*
+  // API wasn't used.)
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
+}
+
+TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
+  ClearFeatureListInstance();
+
+  FieldTrialList field_trial_list(nullptr);
+  scoped_ptr<FeatureList> feature_list(new FeatureList);
+
+  // No features are overridden from the command line yet
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+
+  // Now, enable |kFeatureOffByDefaultName| via the command-line.
+  feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
+
+  // It should now be overridden for the enabled group.
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+
+  // Register a field trial to associate with the feature and ensure that the
+  // results are still the same.
+  feature_list->AssociateReportingFieldTrial(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
+      FieldTrialList::CreateFieldTrial("Trial1", "A"));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+
+  // Now, register a field trial to override |kFeatureOnByDefaultName| state
+  // and check that the function still returns false for that feature.
+  feature_list->RegisterFieldTrialOverride(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
+      FieldTrialList::CreateFieldTrial("Trial2", "A"));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  // Check the expected feature states for good measure.
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
+}
+
+TEST_F(FeatureListTest, AssociateReportingFieldTrial) {
+  struct {
+    const char* enable_features;
+    const char* disable_features;
+    bool expected_enable_trial_created;
+    bool expected_disable_trial_created;
+  } test_cases[] = {
+      // If no enable/disable flags are specified, no trials should be created.
+      {"", "", false, false},
+      // Enabling the feature should result in the enable trial created.
+      {kFeatureOffByDefaultName, "", true, false},
+      // Disabling the feature should result in the disable trial created.
+      {"", kFeatureOffByDefaultName, false, true},
+  };
+
+  const char kTrialName[] = "ForcingTrial";
+  const char kForcedOnGroupName[] = "ForcedOn";
+  const char kForcedOffGroupName[] = "ForcedOff";
+
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    const auto& test_case = test_cases[i];
+    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
+                                    test_case.enable_features,
+                                    test_case.disable_features));
+
+    ClearFeatureListInstance();
+
+    FieldTrialList field_trial_list(nullptr);
+    scoped_ptr<FeatureList> feature_list(new FeatureList);
+    feature_list->InitializeFromCommandLine(test_case.enable_features,
+                                            test_case.disable_features);
+
+    FieldTrial* enable_trial = nullptr;
+    if (feature_list->IsFeatureOverriddenFromCommandLine(
+            kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) {
+      enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName,
+                                                            kForcedOnGroupName);
+      feature_list->AssociateReportingFieldTrial(
+          kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
+          enable_trial);
+    }
+    FieldTrial* disable_trial = nullptr;
+    if (feature_list->IsFeatureOverriddenFromCommandLine(
+            kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)) {
+      disable_trial = base::FieldTrialList::CreateFieldTrial(
+          kTrialName, kForcedOffGroupName);
+      feature_list->AssociateReportingFieldTrial(
+          kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
+          disable_trial);
+    }
+    EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr);
+    EXPECT_EQ(test_case.expected_disable_trial_created,
+              disable_trial != nullptr);
+    RegisterFeatureListInstance(std::move(feature_list));
+
+    EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
+    if (disable_trial) {
+      EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+      EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
+      EXPECT_EQ(kForcedOffGroupName, disable_trial->group_name());
+    } else if (enable_trial) {
+      EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
+      EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
+      EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name());
+    }
+  }
+}
+
+TEST_F(FeatureListTest, GetFeatureOverrides) {
+  ClearFeatureListInstance();
+  FieldTrialList field_trial_list(nullptr);
+  scoped_ptr<FeatureList> feature_list(new FeatureList);
+  feature_list->InitializeFromCommandLine("A,X", "D");
+
+  FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
+  feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
+                                           FeatureList::OVERRIDE_ENABLE_FEATURE,
+                                           trial);
+
+  RegisterFeatureListInstance(feature_list.Pass());
+
+  std::string enable_features;
+  std::string disable_features;
+  FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
+                                                  &disable_features);
+  EXPECT_EQ("A,OffByDefault<Trial,X", SortFeatureListString(enable_features));
+  EXPECT_EQ("D", SortFeatureListString(disable_features));
+}
+
+TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials) {
+  ClearFeatureListInstance();
+  FieldTrialList field_trial_list(nullptr);
+  FieldTrialList::CreateFieldTrial("Trial", "Group");
+  scoped_ptr<FeatureList> feature_list(new FeatureList);
+  feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D");
+  RegisterFeatureListInstance(feature_list.Pass());
+
+  EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
+  EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
+}
+
+}  // namespace base
diff --git a/base/file_descriptor_posix.h b/base/file_descriptor_posix.h
index 376ad39..2a36611 100644
--- a/base/file_descriptor_posix.h
+++ b/base/file_descriptor_posix.h
@@ -14,9 +14,16 @@
 // 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.
+// IMPORTANT: This is primarily intended for use when sending file descriptors
+// over IPC. Even if |auto_close| is true, base::FileDescriptor does NOT close()
+// |fd| when going out of scope. Instead, a consumer of a base::FileDescriptor
+// must invoke close() on |fd| if |auto_close| is true.
+//
+// In the case of IPC, the the IPC subsystem knows to close() |fd| after sending
+// a message that contains a base::FileDescriptor if auto_close == true. On the
+// other end, the receiver must make sure to close() |fd| after it has finished
+// processing the IPC message. See the IPC::ParamTraits<> specialization in
+// ipc/ipc_message_utils.h for all the details.
 // -----------------------------------------------------------------------------
 struct FileDescriptor {
   FileDescriptor() : fd(-1), auto_close(false) {}
diff --git a/base/file_version_info.h b/base/file_version_info.h
index 57b837c..8c1bf92 100644
--- a/base/file_version_info.h
+++ b/base/file_version_info.h
@@ -32,6 +32,17 @@
 // version returns values from the Info.plist as appropriate. TODO(avi): make
 // this a less-obvious Windows-ism.
 
+#if defined(OS_WIN)
+// 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
+// is done as a macro to force inlining of __ImageBase. It used to be inside of
+// a method labeled with __forceinline, but inlining through __forceinline
+// stopped working for Debug builds in VS2013 (http://crbug.com/516359).
+#define CREATE_FILE_VERSION_INFO_FOR_CURRENT_MODULE() \
+    FileVersionInfo::CreateFileVersionInfoForModule( \
+        reinterpret_cast<HMODULE>(&__ImageBase))
+#endif
+
 class BASE_EXPORT FileVersionInfo {
  public:
   virtual ~FileVersionInfo() {}
@@ -46,17 +57,9 @@
 #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.
+  // See CREATE_FILE_VERSION_INFO_FOR_CURRENT_MODULE() helper above for a
+  // CreateFileVersionInfoForCurrentModule() alternative for Windows.
   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.
diff --git a/base/file_version_info_unittest.cc b/base/file_version_info_unittest.cc
index 9b10d04..c5e9859 100644
--- a/base/file_version_info_unittest.cc
+++ b/base/file_version_info_unittest.cc
@@ -32,53 +32,49 @@
 
 #if defined(OS_WIN)
 TEST(FileVersionInfoTest, HardCodedProperties) {
-  const wchar_t* kDLLNames[] = {
-    L"FileVersionInfoTest1.dll"
-  };
+  const wchar_t kDLLName[] = {L"FileVersionInfoTest1.dll"};
 
-  const wchar_t* kExpectedValues[1][15] = {
+  const wchar_t* const kExpectedValues[15] = {
       // FileVersionInfoTest.dll
-      L"Goooooogle",                      // company_name
-      L"Google",                          // company_short_name
-      L"This is the product name",        // product_name
-      L"This is the product short name",  // product_short_name
-      L"The Internal Name",               // internal_name
-      L"4.3.2.1",                         // product_version
-      L"Private build property",          // private_build
-      L"Special build property",          // special_build
+      L"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
+      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]);
+  FilePath dll_path = GetTestDataPath();
+  dll_path = dll_path.Append(kDLLName);
 
-    scoped_ptr<FileVersionInfo> version_info(
-        FileVersionInfo::CreateFileVersionInfo(dll_path));
+  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());
-  }
+  int j = 0;
+  EXPECT_EQ(kExpectedValues[j++], version_info->company_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->company_short_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->product_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->product_short_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->internal_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->product_version());
+  EXPECT_EQ(kExpectedValues[j++], version_info->private_build());
+  EXPECT_EQ(kExpectedValues[j++], version_info->special_build());
+  EXPECT_EQ(kExpectedValues[j++], version_info->comments());
+  EXPECT_EQ(kExpectedValues[j++], version_info->original_filename());
+  EXPECT_EQ(kExpectedValues[j++], version_info->file_description());
+  EXPECT_EQ(kExpectedValues[j++], version_info->file_version());
+  EXPECT_EQ(kExpectedValues[j++], version_info->legal_copyright());
+  EXPECT_EQ(kExpectedValues[j++], version_info->legal_trademarks());
+  EXPECT_EQ(kExpectedValues[j++], version_info->last_change());
 }
 #endif
 
diff --git a/base/files/OWNERS b/base/files/OWNERS
deleted file mode 100644
index b99e8a2..0000000
--- a/base/files/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-rvargas@chromium.org
-
-per-file file_path_watcher*=mnissler@chromium.org
diff --git a/base/files/dir_reader_posix_unittest.cc b/base/files/dir_reader_posix_unittest.cc
index 0685031..2e181b3 100644
--- a/base/files/dir_reader_posix_unittest.cc
+++ b/base/files/dir_reader_posix_unittest.cc
@@ -10,6 +10,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -25,8 +26,9 @@
   if (DirReaderPosix::IsFallback())
     return;
 
-  char kDirTemplate[] = "/tmp/org.chromium.dir-reader-posix-XXXXXX";
-  const char* dir = mkdtemp(kDirTemplate);
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  const char* dir = temp_dir.path().value().c_str();
   ASSERT_TRUE(dir);
 
   const int prev_wd = open(".", O_RDONLY | O_DIRECTORY);
diff --git a/base/files/file.cc b/base/files/file.cc
index 58f80c5..036d43b 100644
--- a/base/files/file.cc
+++ b/base/files/file.cc
@@ -50,28 +50,35 @@
       async_(false) {
 }
 
-File::File(RValue other)
-    : file_(other.object->TakePlatformFile()),
-      path_(other.object->path_),
-      error_details_(other.object->error_details()),
-      created_(other.object->created()),
-      async_(other.object->async_) {
-}
+File::File(File&& other)
+    : file_(other.TakePlatformFile()),
+      tracing_path_(other.tracing_path_),
+      error_details_(other.error_details()),
+      created_(other.created()),
+      async_(other.async_) {}
 
 File::~File() {
   // Go through the AssertIOAllowed logic.
   Close();
 }
 
-File& File::operator=(RValue other) {
-  if (this != other.object) {
-    Close();
-    SetPlatformFile(other.object->TakePlatformFile());
-    path_ = other.object->path_;
-    error_details_ = other.object->error_details();
-    created_ = other.object->created();
-    async_ = other.object->async_;
-  }
+// static
+File File::CreateForAsyncHandle(PlatformFile platform_file) {
+  File file(platform_file);
+  // It would be nice if we could validate that |platform_file| was opened with
+  // FILE_FLAG_OVERLAPPED on Windows but this doesn't appear to be possible.
+  file.async_ = true;
+  return file.Pass();
+}
+
+File& File::operator=(File&& other) {
+  DCHECK_NE(this, &other);
+  Close();
+  SetPlatformFile(other.TakePlatformFile());
+  tracing_path_ = other.tracing_path_;
+  error_details_ = other.error_details();
+  created_ = other.created();
+  async_ = other.async_;
   return *this;
 }
 
@@ -81,9 +88,10 @@
     error_details_ = FILE_ERROR_ACCESS_DENIED;
     return;
   }
-  path_ = path;
+  if (FileTracing::IsCategoryEnabled())
+    tracing_path_ = path;
   SCOPED_FILE_TRACE("Initialize");
-  DoInitialize(flags);
+  DoInitialize(path, flags);
 }
 #endif
 
diff --git a/base/files/file.h b/base/files/file.h
index b21b159..ba4dd34 100644
--- a/base/files/file.h
+++ b/base/files/file.h
@@ -21,7 +21,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_tracing.h"
 #include "base/files/scoped_file.h"
-#include "base/gtest_prod_util.h"
 #include "base/move.h"
 #include "base/time/time.h"
 
@@ -29,8 +28,6 @@
 #include "base/win/scoped_handle.h"
 #endif
 
-FORWARD_DECLARE_TEST(FileTest, MemoryCorruption);
-
 namespace base {
 
 #if defined(OS_WIN)
@@ -56,7 +53,7 @@
 // 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)
+  MOVE_ONLY_TYPE_FOR_CPP_03(File)
 
  public:
   // FLAG_(OPEN|CREATE).* are mutually exclusive. You should specify exactly one
@@ -88,6 +85,7 @@
     FLAG_TERMINAL_DEVICE = 1 << 16,   // Serial port flags.
     FLAG_BACKUP_SEMANTICS = 1 << 17,  // Used on Windows only.
     FLAG_EXECUTE = 1 << 18,           // Used on Windows only.
+    FLAG_SEQUENTIAL_SCAN = 1 << 19,   // Used on Windows only.
   };
 
   // This enum has been recorded in multiple histograms. If the order of the
@@ -171,17 +169,21 @@
   // 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(File&& other);
 
   ~File();
 
-  // Move operator= for C++03 move emulation of this type.
-  File& operator=(RValue other);
+  // Takes ownership of |platform_file|.
+  static File CreateForAsyncHandle(PlatformFile platform_file);
+
+  File& operator=(File&& other);
 
   // Creates or opens the given file.
   void Initialize(const FilePath& path, uint32 flags);
 
+  // Returns |true| if the handle / fd wrapped by this object is valid.  This
+  // method doesn't interact with the file system (and is safe to be called from
+  // ThreadRestrictions::SetIOAllowed(false) threads).
   bool IsValid() const;
 
   // Returns true if a new file was created (or an old one truncated to zero
@@ -303,58 +305,11 @@
   static std::string ErrorToString(Error error);
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
-
   friend class FileTracing::ScopedTrace;
 
-#if defined(OS_POSIX)
-  // Encloses a single ScopedFD, saving a cheap tamper resistent memory checksum
-  // alongside it. This checksum is validated at every access, allowing early
-  // detection of memory corruption.
-
-  // TODO(gavinp): This is in place temporarily to help us debug
-  // https://crbug.com/424562 , which can't be reproduced in valgrind. Remove
-  // this code after we have fixed this issue.
-  class MemoryCheckingScopedFD {
-   public:
-    MemoryCheckingScopedFD();
-    MemoryCheckingScopedFD(int fd);
-    ~MemoryCheckingScopedFD();
-
-    bool is_valid() const { Check(); return file_.is_valid(); }
-    int get() const { Check(); return file_.get(); }
-
-    void reset() { Check(); file_.reset(); UpdateChecksum(); }
-    void reset(int fd) { Check(); file_.reset(fd); UpdateChecksum(); }
-    int release() {
-      Check();
-      int fd = file_.release();
-      UpdateChecksum();
-      return fd;
-    }
-
-   private:
-    FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
-
-    // Computes the checksum for the current value of |file_|. Returns via an
-    // out parameter to guard against implicit conversions of unsigned integral
-    // types.
-    void ComputeMemoryChecksum(unsigned int* out_checksum) const;
-
-    // Confirms that the current |file_| and |file_memory_checksum_| agree,
-    // failing a CHECK if they do not.
-    void Check() const;
-
-    void UpdateChecksum();
-
-    ScopedFD file_;
-    unsigned int file_memory_checksum_;
-  };
-#endif
-
-  // Creates or opens the given file. Only called if |path_| has no
+  // Creates or opens the given file. Only called if |path| has no
   // traversal ('..') components.
-  void DoInitialize(uint32 flags);
+  void DoInitialize(const FilePath& path, uint32 flags);
 
   // TODO(tnagel): Reintegrate into Flush() once histogram isn't needed anymore,
   // cf. issue 473337.
@@ -365,11 +320,12 @@
 #if defined(OS_WIN)
   win::ScopedHandle file_;
 #elif defined(OS_POSIX)
-  MemoryCheckingScopedFD file_;
+  ScopedFD file_;
 #endif
 
-  // Path that |Initialize()| was called with. Only set if safe (i.e. no '..').
-  FilePath path_;
+  // A path to use for tracing purposes. Set if file tracing is enabled during
+  // |Initialize()|.
+  FilePath tracing_path_;
 
   // Object tied to the lifetime of |this| that enables/disables tracing.
   FileTracing::ScopedEnabler trace_enabler_;
@@ -382,3 +338,4 @@
 }  // namespace base
 
 #endif  // BASE_FILES_FILE_H_
+
diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc
index 931d154..90db7f5 100644
--- a/base/files/file_enumerator_win.cc
+++ b/base/files/file_enumerator_win.cc
@@ -30,7 +30,8 @@
   ULARGE_INTEGER size;
   size.HighPart = find_data_.nFileSizeHigh;
   size.LowPart = find_data_.nFileSizeLow;
-  DCHECK_LE(size.QuadPart, std::numeric_limits<int64>::max());
+  DCHECK_LE(size.QuadPart,
+            static_cast<ULONGLONG>(std::numeric_limits<int64>::max()));
   return static_cast<int64>(size.QuadPart);
 }
 
@@ -43,10 +44,10 @@
 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) {
+    : has_find_data_(false),
+      find_handle_(INVALID_HANDLE_VALUE),
+      recursive_(recursive),
+      file_type_(file_type) {
   // INCLUDE_DOT_DOT must not be specified if recursive.
   DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
   memset(&find_data_, 0, sizeof(find_data_));
@@ -57,11 +58,11 @@
                                bool recursive,
                                int file_type,
                                const FilePath::StringType& pattern)
-    : recursive_(recursive),
+    : has_find_data_(false),
+      find_handle_(INVALID_HANDLE_VALUE),
+      recursive_(recursive),
       file_type_(file_type),
-      has_find_data_(false),
-      pattern_(pattern),
-      find_handle_(INVALID_HANDLE_VALUE) {
+      pattern_(pattern) {
   // INCLUDE_DOT_DOT must not be specified if recursive.
   DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
   memset(&find_data_, 0, sizeof(find_data_));
diff --git a/base/files/file_path.cc b/base/files/file_path.cc
index 33d5ca1..18775ed 100644
--- a/base/files/file_path.cc
+++ b/base/files/file_path.cc
@@ -10,9 +10,6 @@
 #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"
@@ -31,7 +28,8 @@
 
 namespace base {
 
-typedef FilePath::StringType StringType;
+using StringType = FilePath::StringType;
+using StringPieceType = FilePath::StringPieceType;
 
 namespace {
 
@@ -45,7 +43,7 @@
 // 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) {
+StringPieceType::size_type FindDriveLetter(StringPieceType path) {
 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
   // This is dependent on an ASCII-based character set, but that's a
   // reasonable assumption.  iswalpha can be too inclusive here.
@@ -59,26 +57,25 @@
 }
 
 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
-bool EqualDriveLetterCaseInsensitive(const StringType& a,
-                                     const StringType& b) {
+bool EqualDriveLetterCaseInsensitive(StringPieceType a, StringPieceType b) {
   size_t a_letter_pos = FindDriveLetter(a);
   size_t b_letter_pos = FindDriveLetter(b);
 
   if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos)
     return a == b;
 
-  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))
+  StringPieceType a_letter(a.substr(0, a_letter_pos + 1));
+  StringPieceType b_letter(b.substr(0, b_letter_pos + 1));
+  if (!StartsWith(a_letter, b_letter, CompareCase::INSENSITIVE_ASCII))
     return false;
 
-  StringType a_rest(a.substr(a_letter_pos + 1));
-  StringType b_rest(b.substr(b_letter_pos + 1));
+  StringPieceType a_rest(a.substr(a_letter_pos + 1));
+  StringPieceType b_rest(b.substr(b_letter_pos + 1));
   return a_rest == b_rest;
 }
 #endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
 
-bool IsPathAbsolute(const StringType& path) {
+bool IsPathAbsolute(StringPieceType path) {
 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
   StringType::size_type letter = FindDriveLetter(path);
   if (letter != StringType::npos) {
@@ -177,7 +174,8 @@
 FilePath::FilePath(const FilePath& that) : path_(that.path_) {
 }
 
-FilePath::FilePath(const StringType& path) : path_(path) {
+FilePath::FilePath(StringPieceType path) {
+  path.CopyToString(&path_);
   StringType::size_type nul_pos = path_.find(kStringTerminator);
   if (nul_pos != StringType::npos)
     path_.erase(nul_pos, StringType::npos);
@@ -279,7 +277,7 @@
   // never case sensitive.
   if ((FindDriveLetter(*parent_comp) != StringType::npos) &&
       (FindDriveLetter(*child_comp) != StringType::npos)) {
-    if (!StartsWith(*parent_comp, *child_comp, false))
+    if (!StartsWith(*parent_comp, *child_comp, CompareCase::INSENSITIVE_ASCII))
       return false;
     ++parent_comp;
     ++child_comp;
@@ -404,7 +402,7 @@
   return FilePath(path_.substr(0, dot));
 }
 
-FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
+FilePath FilePath::InsertBeforeExtension(StringPieceType suffix) const {
   if (suffix.empty())
     return FilePath(path_);
 
@@ -413,27 +411,28 @@
 
   StringType ext = Extension();
   StringType ret = RemoveExtension().value();
-  ret.append(suffix);
+  suffix.AppendToString(&ret);
   ret.append(ext);
   return FilePath(ret);
 }
 
-FilePath FilePath::InsertBeforeExtensionASCII(const StringPiece& suffix)
+FilePath FilePath::InsertBeforeExtensionASCII(StringPiece suffix)
     const {
   DCHECK(IsStringASCII(suffix));
 #if defined(OS_WIN)
-  return InsertBeforeExtension(ASCIIToUTF16(suffix.as_string()));
+  return InsertBeforeExtension(ASCIIToUTF16(suffix));
 #elif defined(OS_POSIX)
-  return InsertBeforeExtension(suffix.as_string());
+  return InsertBeforeExtension(suffix);
 #endif
 }
 
-FilePath FilePath::AddExtension(const StringType& extension) const {
+FilePath FilePath::AddExtension(StringPieceType extension) const {
   if (IsEmptyOrSpecialCase(BaseName().value()))
     return FilePath();
 
   // If the new extension is "" or ".", then just return the current FilePath.
-  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+  if (extension.empty() ||
+      (extension.size() == 1 && extension[0] == kExtensionSeparator))
     return *this;
 
   StringType str = path_;
@@ -441,27 +440,28 @@
       *(str.end() - 1) != kExtensionSeparator) {
     str.append(1, kExtensionSeparator);
   }
-  str.append(extension);
+  extension.AppendToString(&str);
   return FilePath(str);
 }
 
-FilePath FilePath::ReplaceExtension(const StringType& extension) const {
+FilePath FilePath::ReplaceExtension(StringPieceType extension) const {
   if (IsEmptyOrSpecialCase(BaseName().value()))
     return FilePath();
 
   FilePath no_ext = RemoveExtension();
   // If the new extension is "" or ".", then just remove the current extension.
-  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+  if (extension.empty() ||
+      (extension.size() == 1 && extension[0] == kExtensionSeparator))
     return no_ext;
 
   StringType str = no_ext.value();
   if (extension[0] != kExtensionSeparator)
     str.append(1, kExtensionSeparator);
-  str.append(extension);
+  extension.AppendToString(&str);
   return FilePath(str);
 }
 
-bool FilePath::MatchesExtension(const StringType& extension) const {
+bool FilePath::MatchesExtension(StringPieceType extension) const {
   DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
 
   StringType current_extension = Extension();
@@ -472,17 +472,17 @@
   return FilePath::CompareEqualIgnoreCase(extension, current_extension);
 }
 
-FilePath FilePath::Append(const StringType& component) const {
-  const StringType* appended = &component;
+FilePath FilePath::Append(StringPieceType component) const {
+  StringPieceType 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;
+  if (nul_pos != StringPieceType::npos) {
+    component.substr(0, nul_pos).CopyToString(&without_nuls);
+    appended = StringPieceType(without_nuls);
   }
 
-  DCHECK(!IsPathAbsolute(*appended));
+  DCHECK(!IsPathAbsolute(appended));
 
   if (path_.compare(kCurrentDirectory) == 0) {
     // Append normally doesn't do any normalization, but as a special case,
@@ -492,7 +492,7 @@
     // 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);
+    return FilePath(appended);
   }
 
   FilePath new_path(path_);
@@ -501,7 +501,7 @@
   // 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) {
+  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])) {
@@ -512,7 +512,7 @@
     }
   }
 
-  new_path.path_.append(*appended);
+  appended.AppendToString(&new_path.path_);
   return new_path;
 }
 
@@ -520,12 +520,12 @@
   return Append(component.value());
 }
 
-FilePath FilePath::AppendASCII(const StringPiece& component) const {
+FilePath FilePath::AppendASCII(StringPiece component) const {
   DCHECK(base::IsStringASCII(component));
 #if defined(OS_WIN)
-  return Append(ASCIIToUTF16(component.as_string()));
+  return Append(ASCIIToUTF16(component));
 #elif defined(OS_POSIX)
-  return Append(component.as_string());
+  return Append(component);
 #endif
 }
 
@@ -680,17 +680,17 @@
 }
 
 #if defined(OS_WIN)
-// Windows specific implementation of file string comparisons
+// Windows specific implementation of file string comparisons.
 
-int FilePath::CompareIgnoreCase(const StringType& string1,
-                                const StringType& string2) {
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+                                StringPieceType 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();
+  StringPieceType::const_iterator i1 = string1.begin();
+  StringPieceType::const_iterator i2 = string2.begin();
+  StringPieceType::const_iterator string1end = string1.end();
+  StringPieceType::const_iterator string2end = string2.end();
   for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) {
     wchar_t c1 =
         (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i1, 0)));
@@ -709,7 +709,7 @@
 }
 
 #elif defined(OS_MACOSX)
-// Mac OS X specific implementation of file string comparisons
+// Mac OS X specific implementation of file string comparisons.
 
 // cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
 //
@@ -1153,23 +1153,23 @@
   return codepoint;
 }
 
-}  // anonymous namespace
+}  // 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 FilePath::HFSFastUnicodeCompare(StringPieceType string1,
+                                    StringPieceType string2) {
   int length1 = string1.length();
   int length2 = string2.length();
   int index1 = 0;
   int index2 = 0;
 
   for (;;) {
-    int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.c_str(),
+    int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.data(),
                                                       length1,
                                                       &index1);
-    int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.c_str(),
+    int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.data(),
                                                       length2,
                                                       &index2);
     if (codepoint1 != codepoint2)
@@ -1182,11 +1182,11 @@
   }
 }
 
-StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
+StringType FilePath::GetHFSDecomposedForm(StringPieceType string) {
   ScopedCFTypeRef<CFStringRef> cfstring(
       CFStringCreateWithBytesNoCopy(
           NULL,
-          reinterpret_cast<const UInt8*>(string.c_str()),
+          reinterpret_cast<const UInt8*>(string.data()),
           string.length(),
           kCFStringEncodingUTF8,
           false,
@@ -1215,8 +1215,8 @@
   return result;
 }
 
-int FilePath::CompareIgnoreCase(const StringType& string1,
-                                const StringType& string2) {
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+                                StringPieceType string2) {
   // Quick checks for empty strings - these speed things up a bit and make the
   // following code cleaner.
   if (string1.empty())
@@ -1233,7 +1233,7 @@
     ScopedCFTypeRef<CFStringRef> cfstring1(
         CFStringCreateWithBytesNoCopy(
             NULL,
-            reinterpret_cast<const UInt8*>(string1.c_str()),
+            reinterpret_cast<const UInt8*>(string1.data()),
             string1.length(),
             kCFStringEncodingUTF8,
             false,
@@ -1241,7 +1241,7 @@
     ScopedCFTypeRef<CFStringRef> cfstring2(
         CFStringCreateWithBytesNoCopy(
             NULL,
-            reinterpret_cast<const UInt8*>(string2.c_str()),
+            reinterpret_cast<const UInt8*>(string2.data()),
             string2.length(),
             kCFStringEncodingUTF8,
             false,
@@ -1256,11 +1256,12 @@
 
 #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());
+// Generic Posix system comparisons.
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+                                StringPieceType string2) {
+  // Specifically need null termianted strings for this API call.
+  int comparison = strcasecmp(string1.as_string().c_str(),
+                              string2.as_string().c_str());
   if (comparison < 0)
     return -1;
   if (comparison > 0)
@@ -1313,12 +1314,8 @@
 
 #if defined(OS_ANDROID)
 bool FilePath::IsContentUri() const {
-  return StartsWithASCII(path_, "content://", false /*case_sensitive*/);
+  return StartsWith(path_, "content://", base::CompareCase::INSENSITIVE_ASCII);
 }
 #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
index 5225b12..fba2f98 100644
--- a/base/files/file_path.h
+++ b/base/files/file_path.h
@@ -103,6 +103,8 @@
 #define BASE_FILES_FILE_PATH_H_
 
 #include <stddef.h>
+
+#include <iosfwd>
 #include <string>
 #include <vector>
 
@@ -110,7 +112,7 @@
 #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 "base/strings/string_piece.h"
 #include "build/build_config.h"
 
 // Windows-style drive letter support and pathname separator characters can be
@@ -122,11 +124,20 @@
 #define FILE_PATH_USES_WIN_SEPARATORS
 #endif  // OS_WIN
 
-class Pickle;
-class PickleIterator;
+// To print path names portably use PRIsFP (based on PRIuS and friends from
+// C99 and format_macros.h) like this:
+// base::StringPrintf("Path is %" PRIsFP ".\n", path.value().c_str());
+#if defined(OS_POSIX)
+#define PRIsFP "s"
+#elif defined(OS_WIN)
+#define PRIsFP "ls"
+#endif  // OS_WIN
 
 namespace base {
 
+class Pickle;
+class PickleIterator;
+
 // An abstraction to isolate users from the differences between native
 // pathnames on different platforms.
 class BASE_EXPORT FilePath {
@@ -142,6 +153,7 @@
   typedef std::wstring StringType;
 #endif  // OS_WIN
 
+  typedef BasicStringPiece<StringType> StringPieceType;
   typedef StringType::value_type CharType;
 
   // Null-terminated array of separators used to separate components in
@@ -164,7 +176,7 @@
 
   FilePath();
   FilePath(const FilePath& that);
-  explicit FilePath(const StringType& path);
+  explicit FilePath(StringPieceType path);
   ~FilePath();
   FilePath& operator=(const FilePath& that);
 
@@ -266,25 +278,23 @@
   // 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;
+      StringPieceType suffix) const WARN_UNUSED_RESULT;
   FilePath InsertBeforeExtensionASCII(
-      const base::StringPiece& suffix) const WARN_UNUSED_RESULT;
+      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;
+  FilePath AddExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
 
   // Replaces the extension of |file_name| with |extension|.  If |file_name|
   // does not have an extension, then |extension| is added.  If |extension| is
   // empty, then the extension is removed from |file_name|.
   // Returns "" if BaseName() == "." or "..".
-  FilePath ReplaceExtension(
-      const StringType& extension) const WARN_UNUSED_RESULT;
+  FilePath ReplaceExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
 
   // Returns true if the file path matches the specified extension. The test is
   // case insensitive. Don't forget the leading period if appropriate.
-  bool MatchesExtension(const StringType& extension) const;
+  bool MatchesExtension(StringPieceType extension) const;
 
   // Returns a FilePath by appending a separator and the supplied path
   // component to this object's path.  Append takes care to avoid adding
@@ -292,7 +302,7 @@
   // 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(StringPieceType component) const WARN_UNUSED_RESULT;
   FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT;
 
   // Although Windows StringType is std::wstring, since the encoding it uses for
@@ -301,8 +311,7 @@
   // 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;
+  FilePath AppendASCII(StringPiece component) const WARN_UNUSED_RESULT;
 
   // Returns true if this FilePath contains an absolute path.  On Windows, an
   // absolute path begins with either a drive letter specification followed by
@@ -386,14 +395,14 @@
   // 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) {
+  static int CompareIgnoreCase(StringPieceType string1,
+                               StringPieceType string2);
+  static bool CompareEqualIgnoreCase(StringPieceType string1,
+                                     StringPieceType string2) {
     return CompareIgnoreCase(string1, string2) == 0;
   }
-  static bool CompareLessIgnoreCase(const StringType& string1,
-                                    const StringType& string2) {
+  static bool CompareLessIgnoreCase(StringPieceType string1,
+                                    StringPieceType string2) {
     return CompareIgnoreCase(string1, string2) < 0;
   }
 
@@ -403,14 +412,14 @@
   // 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);
+  static StringType GetHFSDecomposedForm(StringPieceType string);
 
   // Special UTF-8 version of FastUnicodeCompare. Cf:
   // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
   // IMPORTANT: The input strings must be in the special HFS decomposed form!
   // (cf. above GetHFSDecomposedForm method)
-  static int HFSFastUnicodeCompare(const StringType& string1,
-                                   const StringType& string2);
+  static int HFSFastUnicodeCompare(StringPieceType string1,
+                                   StringPieceType string2);
 #endif
 
 #if defined(OS_ANDROID)
@@ -433,10 +442,13 @@
   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);
+// This is declared here for use in gtest-based unit tests but is defined in
+// the test_support_base target. Depend on that to use this in your unit test.
+// This should not be used in production code - call ToString() instead.
+void PrintTo(const FilePath& path, std::ostream* out);
+
+}  // namespace base
 
 // Macros for string literal initialization of FilePath::CharType[], and for
 // using a FilePath::CharType[] in a printf-style format string.
diff --git a/base/files/file_path_unittest.cc b/base/files/file_path_unittest.cc
index c162938..bc0e843 100644
--- a/base/files/file_path_unittest.cc
+++ b/base/files/file_path_unittest.cc
@@ -2,12 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
+#if defined(OS_POSIX)
+#include "base/test/scoped_locale.h"
+#endif
+
 // This macro helps avoid wrapped lines in the test structs.
 #define FPL(x) FILE_PATH_LITERAL(x)
 
@@ -1124,6 +1130,10 @@
       "\xEF\xBC\xA1\xEF\xBC\xA2\xEF\xBC\xA3.txt" },
   };
 
+#if !defined(SYSTEM_NATIVE_UTF8) && defined(OS_LINUX)
+  ScopedLocale locale("en_US.UTF-8");
+#endif
+
   for (size_t i = 0; i < arraysize(cases); ++i) {
     // Test FromUTF8Unsafe() works.
     FilePath from_utf8 = FilePath::FromUTF8Unsafe(cases[i].utf8);
@@ -1273,4 +1283,13 @@
 }
 #endif
 
+// Test the PrintTo overload for FilePath (used when a test fails to compare two
+// FilePaths).
+TEST_F(FilePathTest, PrintTo) {
+  std::stringstream ss;
+  FilePath fp(FPL("foo"));
+  base::PrintTo(fp, &ss);
+  EXPECT_EQ("foo", ss.str());
+}
+
 }  // namespace base
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
index 4f132af..834acbc 100644
--- a/base/files/file_path_watcher.h
+++ b/base/files/file_path_watcher.h
@@ -62,9 +62,8 @@
       return task_runner_;
     }
 
-    void set_task_runner(
-        scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-      task_runner_ = task_runner.Pass();
+    void set_task_runner(scoped_refptr<base::SingleThreadTaskRunner> runner) {
+      task_runner_ = std::move(runner);
     }
 
     // Must be called before the PlatformDelegate is deleted.
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
index ba2f1d9..6dfc0a6 100644
--- a/base/files/file_path_watcher_linux.cc
+++ b/base/files/file_path_watcher_linux.cc
@@ -28,6 +28,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
 #include "base/synchronization/lock.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
@@ -167,9 +168,8 @@
   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);
+  // the link target's parent directory. Update |watch_entry| on success.
+  void AddWatchForBrokenSymlink(const FilePath& path, WatchEntry* watch_entry);
 
   bool HasValidWatchVector() const;
 
@@ -513,21 +513,19 @@
 
   // 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;
-        }
-      }
+    watch_entry.watch = g_inotify_reader.Get().AddWatch(path, this);
+    if (watch_entry.watch == InotifyReader::kInvalidWatch) {
+      // Ignore the error code (beyond symlink handling) to attempt to add
+      // watches on accessible children of unreadable directories. Note that
+      // this is a best-effort attempt; we may not catch events in this
+      // scenario.
+      if (IsLink(path))
+        AddWatchForBrokenSymlink(path, &watch_entry);
     }
     if (old_watch != watch_entry.watch)
       g_inotify_reader.Get().RemoveWatch(old_watch, this);
@@ -643,12 +641,12 @@
   recursive_watches_by_path_.clear();
 }
 
-bool FilePathWatcherImpl::AddWatchForBrokenSymlink(const FilePath& path,
+void FilePathWatcherImpl::AddWatchForBrokenSymlink(const FilePath& path,
                                                    WatchEntry* watch_entry) {
   DCHECK_EQ(InotifyReader::kInvalidWatch, watch_entry->watch);
   FilePath link;
   if (!ReadSymbolicLink(path, &link))
-    return false;
+    return;
 
   if (!link.IsAbsolute())
     link = path.DirName().Append(link);
@@ -664,11 +662,10 @@
     // 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;
+    return;
   }
   watch_entry->watch = watch;
   watch_entry->linkname = link.BaseName().value();
-  return true;
 }
 
 bool FilePathWatcherImpl::HasValidWatchVector() const {
diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc
index 081698f..3f37cec 100644
--- a/base/files/file_path_watcher_win.cc
+++ b/base/files/file_path_watcher_win.cc
@@ -106,7 +106,7 @@
   if (!UpdateWatch())
     return false;
 
-  watcher_.StartWatching(handle_, this);
+  watcher_.StartWatchingOnce(handle_, this);
 
   return true;
 }
@@ -198,7 +198,7 @@
 
   // The watch may have been cancelled by the callback.
   if (handle_ != INVALID_HANDLE_VALUE)
-    watcher_.StartWatching(handle_, this);
+    watcher_.StartWatchingOnce(handle_, this);
 }
 
 // static
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index bb49d2d..72fb515 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -22,19 +22,19 @@
 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);
+static_assert(File::FROM_BEGIN == SEEK_SET && File::FROM_CURRENT == SEEK_CUR &&
+                  File::FROM_END == SEEK_END,
+              "whence mapping must match the system headers");
 
 namespace {
 
 #if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
-static int CallFstat(int fd, stat_wrapper_t *sb) {
+int CallFstat(int fd, stat_wrapper_t *sb) {
   ThreadRestrictions::AssertIOAllowed();
   return fstat(fd, sb);
 }
 #else
-static int CallFstat(int fd, stat_wrapper_t *sb) {
+int CallFstat(int fd, stat_wrapper_t *sb) {
   ThreadRestrictions::AssertIOAllowed();
   return fstat64(fd, sb);
 }
@@ -43,15 +43,15 @@
 // 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) {
+bool IsOpenAppend(PlatformFile file) {
   return (fcntl(file, F_GETFL) & O_APPEND) != 0;
 }
 
-static int CallFtruncate(PlatformFile file, int64 length) {
+int CallFtruncate(PlatformFile file, int64 length) {
   return HANDLE_EINTR(ftruncate(file, length));
 }
 
-static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+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/
@@ -68,7 +68,7 @@
 #endif
 }
 
-static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
+File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
   struct flock lock;
   lock.l_type = F_WRLCK;
   lock.l_whence = SEEK_SET;
@@ -80,24 +80,24 @@
 }
 #else  // defined(OS_NACL)
 
-static bool IsOpenAppend(PlatformFile file) {
+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) {
+int CallFtruncate(PlatformFile file, int64 length) {
   NOTIMPLEMENTED();  // NaCl doesn't implement ftruncate.
   return 0;
 }
 
-static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+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) {
+File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
   NOTIMPLEMENTED();  // NaCl doesn't implement flock struct.
   return File::FILE_ERROR_INVALID_OPERATION;
 }
@@ -184,11 +184,11 @@
   SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
 
 #if defined(OS_ANDROID)
-  COMPILE_ASSERT(sizeof(int64) == sizeof(off64_t), off64_t_64_bit);
+  static_assert(sizeof(int64) == sizeof(off64_t), "off64_t must be 64 bits");
   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);
+  static_assert(sizeof(int64) == sizeof(off_t), "off_t must be 64 bits");
   return lseek(file_.get(), static_cast<off_t>(offset),
                static_cast<int>(whence));
 #endif
@@ -360,12 +360,12 @@
 
 File::Error File::Lock() {
   SCOPED_FILE_TRACE("Lock");
-  return CallFctnlFlock(file_.get(), true);
+  return CallFcntlFlock(file_.get(), true);
 }
 
 File::Error File::Unlock() {
   SCOPED_FILE_TRACE("Unlock");
-  return CallFctnlFlock(file_.get(), false);
+  return CallFcntlFlock(file_.get(), false);
 }
 
 File File::Duplicate() {
@@ -420,53 +420,10 @@
   }
 }
 
-File::MemoryCheckingScopedFD::MemoryCheckingScopedFD() {
-  UpdateChecksum();
-}
-
-File::MemoryCheckingScopedFD::MemoryCheckingScopedFD(int fd) : file_(fd) {
-  UpdateChecksum();
-}
-
-File::MemoryCheckingScopedFD::~MemoryCheckingScopedFD() {}
-
-// static
-void File::MemoryCheckingScopedFD::ComputeMemoryChecksum(
-    unsigned int* out_checksum) const {
-  // Use a single iteration of a linear congruentional generator (lcg) to
-  // provide a cheap checksum unlikely to be accidentally matched by a random
-  // memory corruption.
-
-  // By choosing constants that satisfy the Hull-Duebell Theorem on lcg cycle
-  // length, we insure that each distinct fd value maps to a distinct checksum,
-  // which maximises the utility of our checksum.
-
-  // This code uses "unsigned int" throughout for its defined modular semantics,
-  // which implicitly gives us a divisor that is a power of two.
-
-  const unsigned int kMultiplier = 13035 * 4 + 1;
-  COMPILE_ASSERT(((kMultiplier - 1) & 3) == 0, pred_must_be_multiple_of_four);
-  const unsigned int kIncrement = 1595649551;
-  COMPILE_ASSERT(kIncrement & 1, must_be_coprime_to_powers_of_two);
-
-  *out_checksum =
-      static_cast<unsigned int>(file_.get()) * kMultiplier + kIncrement;
-}
-
-void File::MemoryCheckingScopedFD::Check() const {
-  unsigned int computed_checksum;
-  ComputeMemoryChecksum(&computed_checksum);
-  CHECK_EQ(file_memory_checksum_, computed_checksum) << "corrupted fd memory";
-}
-
-void File::MemoryCheckingScopedFD::UpdateChecksum() {
-  ComputeMemoryChecksum(&file_memory_checksum_);
-}
-
 // NaCl doesn't implement system calls to open files directly.
 #if !defined(OS_NACL)
 // TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
-void File::DoInitialize(uint32 flags) {
+void File::DoInitialize(const FilePath& path, uint32 flags) {
   ThreadRestrictions::AssertIOAllowed();
   DCHECK(!IsValid());
 
@@ -514,14 +471,14 @@
   else if (flags & FLAG_APPEND)
     open_flags |= O_APPEND | O_WRONLY;
 
-  COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
+  static_assert(O_RDONLY == 0, "O_RDONLY must equal zero");
 
   int mode = S_IRUSR | S_IWUSR;
 #if defined(OS_CHROMEOS)
   mode |= S_IRGRP | S_IROTH;
 #endif
 
-  int descriptor = HANDLE_EINTR(open(path_.value().c_str(), open_flags, mode));
+  int descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
 
   if (flags & FLAG_OPEN_ALWAYS) {
     if (descriptor < 0) {
@@ -529,7 +486,7 @@
       if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
         open_flags |= O_EXCL;   // together with O_CREAT implies O_NOFOLLOW
 
-      descriptor = HANDLE_EINTR(open(path_.value().c_str(), open_flags, mode));
+      descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode));
       if (descriptor >= 0)
         created_ = true;
     }
@@ -544,7 +501,7 @@
     created_ = true;
 
   if (flags & FLAG_DELETE_ON_CLOSE)
-    unlink(path_.value().c_str());
+    unlink(path.value().c_str());
 
   async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
   error_details_ = FILE_OK;
diff --git a/base/files/file_proxy_unittest.cc b/base/files/file_proxy_unittest.cc
index df0bbc8..ab3e9ae 100644
--- a/base/files/file_proxy_unittest.cc
+++ b/base/files/file_proxy_unittest.cc
@@ -83,10 +83,10 @@
   const FilePath& test_dir_path() const { return dir_.path(); }
   const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
 
+  ScopedTempDir dir_;
   MessageLoopForIO message_loop_;
   Thread file_thread_;
 
-  ScopedTempDir dir_;
   File::Error error_;
   FilePath path_;
   File::Info file_info_;
@@ -287,7 +287,13 @@
   }
 }
 
-TEST_F(FileProxyTest, SetTimes) {
+#if defined(OS_ANDROID)
+// Flaky on Android, see http://crbug.com/489602
+#define MAYBE_SetTimes DISABLED_SetTimes
+#else
+#define MAYBE_SetTimes SetTimes
+#endif
+TEST_F(FileProxyTest, MAYBE_SetTimes) {
   FileProxy proxy(file_task_runner());
   CreateProxy(
       File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_WRITE_ATTRIBUTES,
diff --git a/base/files/file_tracing.cc b/base/files/file_tracing.cc
index a1919c4..92a5780 100644
--- a/base/files/file_tracing.cc
+++ b/base/files/file_tracing.cc
@@ -13,6 +13,11 @@
 }
 
 // static
+bool FileTracing::IsCategoryEnabled() {
+  return g_provider && g_provider->FileTracingCategoryIsEnabled();
+}
+
+// static
 void FileTracing::SetProvider(FileTracing::Provider* provider) {
   g_provider = provider;
 }
@@ -27,30 +32,18 @@
     g_provider->FileTracingDisable(this);
 }
 
-FileTracing::ScopedTrace::ScopedTrace() : initialized_(false) {}
+FileTracing::ScopedTrace::ScopedTrace() : id_(nullptr) {}
 
 FileTracing::ScopedTrace::~ScopedTrace() {
-  if (initialized_ && g_provider) {
-    g_provider->FileTracingEventEnd(
-        name_, &file_->trace_enabler_, file_->path_, size_);
-  }
-}
-
-bool FileTracing::ScopedTrace::ShouldInitialize() const {
-  return g_provider && g_provider->FileTracingCategoryIsEnabled();
+  if (id_ && g_provider)
+    g_provider->FileTracingEventEnd(name_, id_);
 }
 
 void FileTracing::ScopedTrace::Initialize(
     const char* name, File* file, int64 size) {
-  file_ = file;
+  id_ = &file->trace_enabler_;
   name_ = name;
-  size_ = size;
-  initialized_ = true;
-
-  if (g_provider) {
-    g_provider->FileTracingEventBegin(
-        name_, &file_->trace_enabler_, file_->path_, size_);
-  }
+  g_provider->FileTracingEventBegin(name_, id_, file->tracing_path_, size);
 }
 
 }  // namespace base
diff --git a/base/files/file_tracing.h b/base/files/file_tracing.h
index 8452037..d37c21d 100644
--- a/base/files/file_tracing.h
+++ b/base/files/file_tracing.h
@@ -13,7 +13,7 @@
 
 #define SCOPED_FILE_TRACE_WITH_SIZE(name, size) \
     FileTracing::ScopedTrace scoped_file_trace; \
-    if (scoped_file_trace.ShouldInitialize()) \
+    if (FileTracing::IsCategoryEnabled()) \
       scoped_file_trace.Initialize(FILE_TRACING_PREFIX "::" name, this, size)
 
 #define SCOPED_FILE_TRACE(name) SCOPED_FILE_TRACE_WITH_SIZE(name, 0)
@@ -25,8 +25,13 @@
 
 class BASE_EXPORT FileTracing {
  public:
+  // Whether the file tracing category is enabled.
+  static bool IsCategoryEnabled();
+
   class Provider {
    public:
+    virtual ~Provider() = default;
+
     // Whether the file tracing category is currently enabled.
     virtual bool FileTracingCategoryIsEnabled() const = 0;
 
@@ -37,16 +42,13 @@
     virtual void FileTracingDisable(void* id) = 0;
 
     // Begins an event for |id| with |name|. |path| tells where in the directory
-    // structure the event is happening (and may be blank). |size| is reported
-    // if not 0.
+    // structure the event is happening (and may be blank). |size| is the number
+    // of bytes involved in the event.
     virtual void FileTracingEventBegin(
         const char* name, void* id, const FilePath& path, int64 size) = 0;
 
-    // Ends an event for |id| with |name|. |path| tells where in the directory
-    // structure the event is happening (and may be blank). |size| is reported
-    // if not 0.
-    virtual void FileTracingEventEnd(
-        const char* name, void* id, const FilePath& path, int64 size) = 0;
+    // Ends an event for |id| with |name|.
+    virtual void FileTracingEventEnd(const char* name, void* id) = 0;
   };
 
   // Sets a global file tracing provider to query categories and record events.
@@ -64,26 +66,21 @@
     ScopedTrace();
     ~ScopedTrace();
 
-    // Whether this trace should be initialized or not.
-    bool ShouldInitialize() const;
-
-    // Called only if the tracing category is enabled.
-    void Initialize(const char* event, File* file, int64 size);
+    // Called only if the tracing category is enabled. |name| is the name of the
+    // event to trace (e.g. "Read", "Write") and must have an application
+    // lifetime (e.g. static or literal). |file| is the file being traced; must
+    // outlive this class. |size| is the size (in bytes) of this event.
+    void Initialize(const char* name, File* file, int64 size);
 
    private:
-    // True if |Initialize()| has been called. Don't touch |path_|, |event_|,
-    // or |bytes_| if |initialized_| is false.
-    bool initialized_;
+    // The ID of this trace. Based on the |file| passed to |Initialize()|. Must
+    // outlive this class.
+    void* id_;
 
-    // The event name to trace (e.g. "Read", "Write"). Prefixed with "File".
+    // The name of the event to trace (e.g. "Read", "Write"). Prefixed with
+    // "File".
     const char* name_;
 
-    // The file being traced. Must outlive this class.
-    File* file_;
-
-    // The size (in bytes) of this trace. Not reported if 0.
-    int64 size_;
-
     DISALLOW_COPY_AND_ASSIGN(ScopedTrace);
   };
 
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc
index 5c59424..67dbbfd 100644
--- a/base/files/file_unittest.cc
+++ b/base/files/file_unittest.cc
@@ -5,7 +5,6 @@
 #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"
 
@@ -495,7 +494,7 @@
 
   base::File dir(
       ::CreateFile(empty_dir.value().c_str(),
-                   FILE_ALL_ACCESS,
+                   GENERIC_READ | GENERIC_WRITE,
                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                    NULL,
                    OPEN_EXISTING,
@@ -510,71 +509,3 @@
   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
index 32dab6b..4b6b888 100644
--- a/base/files/file_util.cc
+++ b/base/files/file_util.cc
@@ -22,6 +22,7 @@
 
 namespace base {
 
+#if !defined(OS_NACL_NONSFI)
 namespace {
 
 // The maximum number of 'uniquified' files we will try to create.
@@ -120,6 +121,7 @@
 
   return true;
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 bool ReadFileToString(const FilePath& path,
                       std::string* contents,
@@ -162,6 +164,7 @@
   return ReadFileToString(path, contents, std::numeric_limits<size_t>::max());
 }
 
+#if !defined(OS_NACL_NONSFI)
 bool IsDirectoryEmpty(const FilePath& dir_path) {
   FileEnumerator files(dir_path, false,
       FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
@@ -207,6 +210,7 @@
 
   return file.SetTimes(last_accessed, last_modified);
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 bool CloseFile(FILE* file) {
   if (file == NULL)
@@ -214,6 +218,7 @@
   return fclose(file) == 0;
 }
 
+#if !defined(OS_NACL_NONSFI)
 bool TruncateFile(FILE* file) {
   if (file == NULL)
     return false;
@@ -251,5 +256,6 @@
 
   return -1;
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 }  // namespace base
diff --git a/base/files/file_util_mac.mm b/base/files/file_util_mac.mm
index acac8d7..a701bad 100644
--- a/base/files/file_util_mac.mm
+++ b/base/files/file_util_mac.mm
@@ -4,8 +4,8 @@
 
 #include "base/files/file_util.h"
 
-#import <Foundation/Foundation.h>
 #include <copyfile.h>
+#import <Foundation/Foundation.h>
 
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index b4a64ba..eb8620d 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -24,8 +24,6 @@
 #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"
@@ -478,16 +476,6 @@
 
 #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;
@@ -651,6 +639,7 @@
   results->FromStat(file_info);
   return true;
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 FILE* OpenFile(const FilePath& filename, const char* mode) {
   ThreadRestrictions::AssertIOAllowed();
@@ -685,7 +674,7 @@
 
 int WriteFile(const FilePath& filename, const char* data, int size) {
   ThreadRestrictions::AssertIOAllowed();
-  int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0640));
+  int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666));
   if (fd < 0)
     return -1;
 
@@ -710,6 +699,8 @@
   return true;
 }
 
+#if !defined(OS_NACL_NONSFI)
+
 bool AppendToFile(const FilePath& filename, const char* data, int size) {
   ThreadRestrictions::AssertIOAllowed();
   bool ret = true;
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index b107b0f..933cb7f 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -134,7 +134,7 @@
   ReparsePoint(const FilePath& source, const FilePath& target) {
     dir_.Set(
       ::CreateFile(source.value().c_str(),
-                   FILE_ALL_ACCESS,
+                   GENERIC_READ | GENERIC_WRITE,
                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                    NULL,
                    OPEN_EXISTING,
@@ -244,15 +244,6 @@
   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.
@@ -331,7 +322,7 @@
   // 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());
+  *temp_base_a.begin() = ToUpperASCII(*temp_base_a.begin());
   base_a = FilePath(temp_base_a);
 #endif
   ASSERT_TRUE(CreateDirectory(base_a));
@@ -435,8 +426,8 @@
 
 TEST_F(FileUtilTest, DevicePathToDriveLetter) {
   // Get a drive letter.
-  std::wstring real_drive_letter = temp_dir_.path().value().substr(0, 2);
-  StringToUpperASCII(&real_drive_letter);
+  string16 real_drive_letter =
+      ToUpperASCII(temp_dir_.path().value().substr(0, 2));
   if (!isalpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) {
     LOG(ERROR) << "Can't get a drive letter to test with.";
     return;
@@ -537,8 +528,8 @@
   // 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));
+  FilePermissionRestorer long_test_dir_restorer(long_test_dir);
+  ASSERT_TRUE(MakeFileUnreadable(long_test_dir));
 
   // Use the short form of the directory to create a temporary filename.
   ASSERT_TRUE(CreateTemporaryFileInDir(
@@ -2101,7 +2092,7 @@
   EXPECT_EQ(0u, data.length());
 
   // Delete test file.
-  EXPECT_TRUE(base::DeleteFile(file_path, false));
+  EXPECT_TRUE(DeleteFile(file_path, false));
 
   data = "temp";
   EXPECT_FALSE(ReadFileToString(file_path, &data));
@@ -2235,24 +2226,17 @@
                                      .AppendASCII("not")
                                      .AppendASCII("exist");
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, does_not_exist, uid_, ok_gids_));
+      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_));
+  EXPECT_FALSE(VerifyPathControlledByUser(sub_dir_, base_dir_, uid_, ok_gids_));
 
   // An empty base path will fail to be a prefix for any path.
   FilePath empty;
-  EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          empty, base_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(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_));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
 }
 
 TEST_F(VerifyPathControlledByUserTest, Symlinks) {
@@ -2264,11 +2248,9 @@
       << "Failed to create symlink.";
 
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, file_link, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, file_link, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          file_link, file_link, uid_, ok_gids_));
+      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");
@@ -2278,18 +2260,15 @@
   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(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_));
+  EXPECT_FALSE(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_));
+  EXPECT_TRUE(VerifyPathControlledByUser(file_path_with_link,
+                                         file_path_with_link, uid_, ok_gids_));
 }
 
 TEST_F(VerifyPathControlledByUserTest, OwnershipChecks) {
@@ -2305,37 +2284,26 @@
       ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
 
   // We control these paths.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   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_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Another user does not control these paths.
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, bad_uid, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, sub_dir_, bad_uid, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, bad_uid, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, bad_uid, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, bad_uid, ok_gids_));
+      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_));
+      VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, bad_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, bad_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
 }
 
 TEST_F(VerifyPathControlledByUserTest, GroupWriteTest) {
@@ -2348,68 +2316,41 @@
       ChangePosixFilePermissions(text_file_, 0u, S_IWOTH|S_IWGRP));
 
   // Any group is okay because the path is not group-writable.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_TRUE(
-      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_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, bad_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, 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_));
+      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));
-
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, no_gids));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, text_file_, uid_, no_gids));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, no_gids));
 
   // Make all files and directories writable by their group.
-  ASSERT_NO_FATAL_FAILURE(
-      ChangePosixFilePermissions(base_dir_, S_IWGRP, 0u));
-  ASSERT_NO_FATAL_FAILURE(
-      ChangePosixFilePermissions(sub_dir_, S_IWGRP, 0u));
-  ASSERT_NO_FATAL_FAILURE(
-      ChangePosixFilePermissions(text_file_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(base_dir_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(sub_dir_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(text_file_, S_IWGRP, 0u));
 
   // Now |ok_gids_| works, but |bad_gids_| fails.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_TRUE(
-      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_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, bad_gids_));
+      VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, bad_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, bad_gids_));
+      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.
@@ -2421,14 +2362,11 @@
       std::inserter(multiple_gids, multiple_gids.begin()));
 
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, multiple_gids));
+      VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, multiple_gids));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, multiple_gids));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, multiple_gids));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, multiple_gids));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, multiple_gids));
 }
 
 TEST_F(VerifyPathControlledByUserTest, WriteBitChecks) {
@@ -2441,94 +2379,63 @@
       ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
 
   // Initialy, we control all parts of the path.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_TRUE(
-      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_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Make base_dir_ world-writable.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(base_dir_, S_IWOTH, 0u));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      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_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Make sub_dir_ world writable.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(sub_dir_, S_IWOTH, 0u));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, 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_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Make text_file_ world writable.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(text_file_, S_IWOTH, 0u));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, 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_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Make sub_dir_ non-world writable.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, 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_));
+      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_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Back to the initial state: Nothing is writable, so every path
   // should pass.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_TRUE(
-      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_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 }
 
 #if defined(OS_ANDROID)
@@ -2545,7 +2452,7 @@
 
   // Insert the image into MediaStore. MediaStore will do some conversions, and
   // return the content URI.
-  FilePath path = base::InsertImageIntoMediaStore(image_file);
+  FilePath path = InsertImageIntoMediaStore(image_file);
   EXPECT_TRUE(path.IsContentUri());
   EXPECT_TRUE(PathExists(path));
   // The file size may not equal to the input image as MediaStore may convert
@@ -2581,9 +2488,9 @@
   char c = 0;
   ASSERT_EQ(0, pipe(fds));
   const int write_end = fds[1];
-  base::ScopedFD read_end_closer(fds[0]);
+  ScopedFD read_end_closer(fds[0]);
   {
-    base::ScopedFD write_end_closer(fds[1]);
+    ScopedFD write_end_closer(fds[1]);
   }
   // This is the only thread. This file descriptor should no longer be valid.
   int ret = close(write_end);
@@ -2597,14 +2504,14 @@
 
 #if defined(GTEST_HAS_DEATH_TEST)
 void CloseWithScopedFD(int fd) {
-  base::ScopedFD fd_closer(fd);
+  ScopedFD fd_closer(fd);
 }
 #endif
 
 TEST(ScopedFD, ScopedFDCrashesOnCloseFailure) {
   int fds[2];
   ASSERT_EQ(0, pipe(fds));
-  base::ScopedFD read_end_closer(fds[0]);
+  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.
diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc
index e254232..428b7a6 100644
--- a/base/files/file_util_win.cc
+++ b/base/files/file_util_win.cc
@@ -9,6 +9,7 @@
 #include <psapi.h>
 #include <shellapi.h>
 #include <shlobj.h>
+#include <stdint.h>
 #include <time.h>
 
 #include <algorithm>
@@ -36,6 +37,36 @@
 const DWORD kFileShareAll =
     FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
 
+// Deletes all files and directories in a path.
+// Returns false on the first failure it encounters.
+bool DeleteFileRecursive(const FilePath& path,
+                         const FilePath::StringType& pattern,
+                         bool recursive) {
+  FileEnumerator traversal(path, false,
+                           FileEnumerator::FILES | FileEnumerator::DIRECTORIES,
+                           pattern);
+  for (FilePath current = traversal.Next(); !current.empty();
+       current = traversal.Next()) {
+    // Try to clear the read-only bit if we find it.
+    FileEnumerator::FileInfo info = traversal.GetInfo();
+    if ((info.find_data().dwFileAttributes & FILE_ATTRIBUTE_READONLY) &&
+        (recursive || !info.IsDirectory())) {
+      SetFileAttributes(
+          current.value().c_str(),
+          info.find_data().dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
+    }
+
+    if (info.IsDirectory()) {
+      if (recursive && (!DeleteFileRecursive(current, pattern, true) ||
+                        !RemoveDirectory(current.value().c_str())))
+        return false;
+    } else if (!::DeleteFile(current.value().c_str())) {
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace
 
 FilePath MakeAbsoluteFilePath(const FilePath& input) {
@@ -49,56 +80,36 @@
 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)
+  if (path.value().length() >= MAX_PATH)
     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);
+  // Handle any path with wildcards.
+  if (path.BaseName().value().find_first_of(L"*?") !=
+      FilePath::StringType::npos) {
+    return DeleteFileRecursive(path.DirName(), path.BaseName().value(),
+                               recursive);
+  }
+  DWORD attr = GetFileAttributes(path.value().c_str());
+  // We're done if we can't find the path.
+  if (attr == INVALID_FILE_ATTRIBUTES)
+    return true;
+  // We may need to clear the read-only bit.
+  if ((attr & FILE_ATTRIBUTE_READONLY) &&
+      !SetFileAttributes(path.value().c_str(),
+                          attr & ~FILE_ATTRIBUTE_READONLY)) {
+    return false;
+  }
+  // Directories are handled differently if they're recursive.
+  if (!(attr & FILE_ATTRIBUTE_DIRECTORY))
+    return !!::DeleteFile(path.value().c_str());
+  // Handle a simple, single file delete.
+  if (!recursive || DeleteFileRecursive(path, L"*", true))
+    return !!RemoveDirectory(path.value().c_str());
+
+  return false;
 }
 
 bool DeleteFileAfterReboot(const FilePath& path) {
@@ -349,7 +360,8 @@
     new_dir_name.assign(prefix);
     new_dir_name.append(IntToString16(GetCurrentProcId()));
     new_dir_name.push_back('_');
-    new_dir_name.append(IntToString16(RandInt(0, kint16max)));
+    new_dir_name.append(
+        IntToString16(RandInt(0, std::numeric_limits<int16_t>::max())));
 
     path_to_create = base_dir.Append(new_dir_name);
     if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
diff --git a/base/files/file_win.cc b/base/files/file_win.cc
index 9792852..c2cc3ab 100644
--- a/base/files/file_win.cc
+++ b/base/files/file_win.cc
@@ -13,9 +13,10 @@
 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);
+static_assert(File::FROM_BEGIN == FILE_BEGIN &&
+                  File::FROM_CURRENT == FILE_CURRENT &&
+                  File::FROM_END == FILE_END,
+              "whence mapping must match the system headers");
 
 bool File::IsValid() const {
   return file_.IsValid();
@@ -308,7 +309,7 @@
   }
 }
 
-void File::DoInitialize(uint32 flags) {
+void File::DoInitialize(const FilePath& path, uint32 flags) {
   ThreadRestrictions::AssertIOAllowed();
   DCHECK(!IsValid());
 
@@ -375,8 +376,10 @@
     create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
   if (flags & FLAG_BACKUP_SEMANTICS)
     create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
+  if (flags & FLAG_SEQUENTIAL_SCAN)
+    create_flags |= FILE_FLAG_SEQUENTIAL_SCAN;
 
-  file_.Set(CreateFile(path_.value().c_str(), access, sharing, NULL,
+  file_.Set(CreateFile(path.value().c_str(), access, sharing, NULL,
                        disposition, create_flags, NULL));
 
   if (file_.IsValid()) {
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index 814fc7b..4af7137 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -5,8 +5,8 @@
 #include "base/files/important_file_writer.h"
 
 #include <stdio.h>
-
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/critical_closure.h"
@@ -16,6 +16,7 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/task_runner.h"
@@ -47,8 +48,7 @@
                 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;
+  DPLOG(WARNING) << "temp file failure: " << path.value() << " : " << message;
 }
 
 // Helper function to call WriteFileAtomically() with a scoped_ptr<std::string>.
@@ -72,16 +72,16 @@
     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);
+  strlcpy(file_info.path, path.value().c_str(), arraysize(file_info.path));
+  debug::Alias(&file_info);
 #endif
+
   // Write the data to a temp file then rename to avoid data loss if we crash
   // while writing the file. Ensure that the temp file is on the same volume
   // as target file, so it can be moved in one step, and that the temp file
   // is securely created.
   FilePath tmp_file_path;
-  if (!base::CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) {
+  if (!CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) {
     LogFailure(path, FAILED_CREATING, "could not create temporary file");
     return false;
   }
@@ -92,29 +92,28 @@
     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()));
+  // If this fails in the wild, something really bad is going on.
+  const int data_length = checked_cast<int32_t>(data.length());
+  int bytes_written = tmp_file.Write(0, data.data(), data_length);
   bool flush_success = tmp_file.Flush();
   tmp_file.Close();
 
-  if (bytes_written < static_cast<int>(data.length())) {
+  if (bytes_written < data_length) {
     LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" +
                IntToString(bytes_written));
-    base::DeleteFile(tmp_file_path, false);
+    DeleteFile(tmp_file_path, false);
     return false;
   }
 
   if (!flush_success) {
     LogFailure(path, FAILED_FLUSHING, "error flushing");
-    base::DeleteFile(tmp_file_path, false);
+    DeleteFile(tmp_file_path, false);
     return false;
   }
 
-  if (!base::ReplaceFile(tmp_file_path, path, NULL)) {
+  if (!ReplaceFile(tmp_file_path, path, nullptr)) {
     LogFailure(path, FAILED_RENAMING, "could not rename temporary file");
-    base::DeleteFile(tmp_file_path, false);
+    DeleteFile(tmp_file_path, false);
     return false;
   }
 
@@ -123,11 +122,21 @@
 
 ImportantFileWriter::ImportantFileWriter(
     const FilePath& path,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    const scoped_refptr<SequencedTaskRunner>& task_runner)
+    : ImportantFileWriter(
+        path,
+        task_runner,
+        TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)) {
+}
+
+ImportantFileWriter::ImportantFileWriter(
+    const FilePath& path,
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    TimeDelta interval)
     : path_(path),
       task_runner_(task_runner),
-      serializer_(NULL),
-      commit_interval_(TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)),
+      serializer_(nullptr),
+      commit_interval_(interval),
       weak_factory_(this) {
   DCHECK(CalledOnValidThread());
   DCHECK(task_runner_);
@@ -147,7 +156,7 @@
 
 void ImportantFileWriter::WriteNow(scoped_ptr<std::string> data) {
   DCHECK(CalledOnValidThread());
-  if (data->length() > static_cast<size_t>(kint32max)) {
+  if (!IsValueInRangeForNumericType<int32_t>(data->length())) {
     NOTREACHED();
     return;
   }
@@ -182,16 +191,16 @@
   DCHECK(serializer_);
   scoped_ptr<std::string> data(new std::string);
   if (serializer_->SerializeData(data.get())) {
-    WriteNow(data.Pass());
+    WriteNow(std::move(data));
   } else {
     DLOG(WARNING) << "failed to serialize data to be saved in "
-                  << path_.value().c_str();
+                  << path_.value();
   }
-  serializer_ = NULL;
+  serializer_ = nullptr;
 }
 
 void ImportantFileWriter::RegisterOnNextSuccessfulWriteCallback(
-    const base::Closure& on_next_successful_write) {
+    const Closure& on_next_successful_write) {
   DCHECK(on_next_successful_write_.is_null());
   on_next_successful_write_ = on_next_successful_write;
 }
@@ -203,7 +212,7 @@
   // 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(
+    return PostTaskAndReplyWithResult(
         task_runner_.get(),
         FROM_HERE,
         MakeCriticalClosure(task),
@@ -212,7 +221,7 @@
   }
   return task_runner_->PostTask(
       FROM_HERE,
-      MakeCriticalClosure(base::Bind(IgnoreResult(task))));
+      MakeCriticalClosure(Bind(IgnoreResult(task))));
 }
 
 void ImportantFileWriter::ForwardSuccessfulWrite(bool result) {
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
index 99f1a7c..7c6160a 100644
--- a/base/files/important_file_writer.h
+++ b/base/files/important_file_writer.h
@@ -62,9 +62,13 @@
   // |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);
+  ImportantFileWriter(const FilePath& path,
+                      const scoped_refptr<SequencedTaskRunner>& task_runner);
+
+  // Same as above, but with a custom commit interval.
+  ImportantFileWriter(const FilePath& path,
+                      const scoped_refptr<SequencedTaskRunner>& task_runner,
+                      TimeDelta interval);
 
   // You have to ensure that there are no pending writes at the moment
   // of destruction.
@@ -77,7 +81,7 @@
   bool HasPendingWrite() const;
 
   // Save |data| to target filename. Does not block. If there is a pending write
-  // scheduled by ScheduleWrite, it is cancelled.
+  // 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
@@ -94,16 +98,12 @@
   // 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);
+      const 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);
@@ -113,22 +113,22 @@
   void ForwardSuccessfulWrite(bool result);
 
   // Invoked once and then reset on the next successful write event.
-  base::Closure on_next_successful_write_;
+  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_;
+  const scoped_refptr<SequencedTaskRunner> task_runner_;
 
   // Timer used to schedule commit after ScheduleWrite.
-  OneShotTimer<ImportantFileWriter> timer_;
+  OneShotTimer 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_;
+  const TimeDelta commit_interval_;
 
   WeakPtrFactory<ImportantFileWriter> weak_factory_;
 
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
index d376cdc..71900c9 100644
--- a/base/files/important_file_writer_unittest.cc
+++ b/base/files/important_file_writer_unittest.cc
@@ -145,8 +145,9 @@
 }
 
 TEST_F(ImportantFileWriterTest, ScheduleWrite) {
-  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
-  writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+  ImportantFileWriter writer(file_,
+                             ThreadTaskRunnerHandle::Get(),
+                             TimeDelta::FromMilliseconds(25));
   EXPECT_FALSE(writer.HasPendingWrite());
   DataSerializer serializer("foo");
   writer.ScheduleWrite(&serializer);
@@ -177,8 +178,9 @@
 }
 
 TEST_F(ImportantFileWriterTest, BatchingWrites) {
-  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
-  writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+  ImportantFileWriter writer(file_,
+                             ThreadTaskRunnerHandle::Get(),
+                             TimeDelta::FromMilliseconds(25));
   DataSerializer foo("foo"), bar("bar"), baz("baz");
   writer.ScheduleWrite(&foo);
   writer.ScheduleWrite(&bar);
diff --git a/base/files/memory_mapped_file.cc b/base/files/memory_mapped_file.cc
index 891fcff..227a41f 100644
--- a/base/files/memory_mapped_file.cc
+++ b/base/files/memory_mapped_file.cc
@@ -10,23 +10,18 @@
 
 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);
-}
+const MemoryMappedFile::Region MemoryMappedFile::Region::kWholeFile = {0, 0};
 
 bool MemoryMappedFile::Region::operator==(
     const MemoryMappedFile::Region& other) const {
   return other.offset == offset && other.size == size;
 }
 
+bool MemoryMappedFile::Region::operator!=(
+    const MemoryMappedFile::Region& other) const {
+  return other.offset != offset || other.size != size;
+}
+
 MemoryMappedFile::~MemoryMappedFile() {
   CloseHandles();
 }
@@ -59,6 +54,11 @@
   if (IsValid())
     return false;
 
+  if (region != Region::kWholeFile) {
+    DCHECK_GE(region.offset, 0);
+    DCHECK_GT(region.size, 0);
+  }
+
   file_ = file.Pass();
 
   if (!MapFileRegionToMemory(region)) {
diff --git a/base/files/memory_mapped_file.h b/base/files/memory_mapped_file.h
index 8a7f045..9ff29b9 100644
--- a/base/files/memory_mapped_file.h
+++ b/base/files/memory_mapped_file.h
@@ -28,20 +28,14 @@
   struct BASE_EXPORT Region {
     static const Region kWholeFile;
 
-    Region(int64 offset, int64 size);
-
     bool operator==(const Region& other) const;
+    bool operator!=(const Region& other) const;
 
     // Start of the region (measured in bytes from the beginning of the file).
     int64 offset;
 
     // Length of the region in bytes.
     int64 size;
-
-   private:
-    // 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
diff --git a/base/files/memory_mapped_file_unittest.cc b/base/files/memory_mapped_file_unittest.cc
index d0833b5..1812d88 100644
--- a/base/files/memory_mapped_file_unittest.cc
+++ b/base/files/memory_mapped_file_unittest.cc
@@ -18,7 +18,7 @@
   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();
+  return buf;
 }
 
 // Check that the watermark sequence is consistent with the |offset| provided.
@@ -107,7 +107,8 @@
   MemoryMappedFile map;
 
   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
-  map.Initialize(file.Pass(), MemoryMappedFile::Region(0, kPartialSize));
+  MemoryMappedFile::Region region = {0, kPartialSize};
+  map.Initialize(file.Pass(), region);
   ASSERT_EQ(kPartialSize, map.length());
   ASSERT_TRUE(map.data() != NULL);
   EXPECT_TRUE(map.IsValid());
@@ -122,7 +123,8 @@
   MemoryMappedFile map;
 
   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
-  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  MemoryMappedFile::Region region = {kOffset, kPartialSize};
+  map.Initialize(file.Pass(), region);
   ASSERT_EQ(kPartialSize, map.length());
   ASSERT_TRUE(map.data() != NULL);
   EXPECT_TRUE(map.IsValid());
@@ -138,7 +140,8 @@
   MemoryMappedFile map;
 
   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
-  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  MemoryMappedFile::Region region = {kOffset, kPartialSize};
+  map.Initialize(file.Pass(), region);
   ASSERT_EQ(kPartialSize, map.length());
   ASSERT_TRUE(map.data() != NULL);
   EXPECT_TRUE(map.IsValid());
@@ -154,7 +157,8 @@
   MemoryMappedFile map;
 
   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
-  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  MemoryMappedFile::Region region = {kOffset, kPartialSize};
+  map.Initialize(file.Pass(), region);
   ASSERT_EQ(kPartialSize, map.length());
   ASSERT_TRUE(map.data() != NULL);
   EXPECT_TRUE(map.IsValid());
diff --git a/base/files/memory_mapped_file_win.cc b/base/files/memory_mapped_file_win.cc
index 4e7e934..8585906 100644
--- a/base/files/memory_mapped_file_win.cc
+++ b/base/files/memory_mapped_file_win.cc
@@ -32,7 +32,7 @@
   if (!file_mapping_.IsValid())
     return false;
 
-  LARGE_INTEGER map_start = {0};
+  LARGE_INTEGER map_start = {};
   SIZE_T map_size = 0;
   int32 data_offset = 0;
 
diff --git a/base/guid_unittest.cc b/base/guid_unittest.cc
index 4eda7f6..1c5d393 100644
--- a/base/guid_unittest.cc
+++ b/base/guid_unittest.cc
@@ -9,6 +9,8 @@
 #include "base/strings/string_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace base {
+
 #if defined(OS_POSIX)
 
 namespace {
@@ -16,23 +18,22 @@
 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' &&
+  return IsValidGUID(guid) && guid[14] == '4' &&
          (guid[19] == '8' || guid[19] == '9' || guid[19] == 'A' ||
           guid[19] == 'a' || guid[19] == 'B' || guid[19] == 'b');
 }
 
 }  // namespace
 
-
 TEST(GUIDTest, GUIDGeneratesAllZeroes) {
   uint64 bytes[] = { 0, 0 };
-  std::string clientid = base::RandomDataToGUIDString(bytes);
+  std::string clientid = RandomDataToGUIDString(bytes);
   EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid);
 }
 
 TEST(GUIDTest, GUIDGeneratesCorrectly) {
   uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL };
-  std::string clientid = base::RandomDataToGUIDString(bytes);
+  std::string clientid = RandomDataToGUIDString(bytes);
   EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid);
 }
 #endif
@@ -40,18 +41,18 @@
 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)));
+    std::string guid = GenerateGUID();
+    EXPECT_TRUE(IsValidGUID(guid));
+    EXPECT_TRUE(IsValidGUID(ToLowerASCII(guid)));
+    EXPECT_TRUE(IsValidGUID(ToUpperASCII(guid)));
   }
 }
 
 TEST(GUIDTest, GUIDBasicUniqueness) {
   const int kIterations = 10;
   for (int it = 0; it < kIterations; ++it) {
-    std::string guid1 = base::GenerateGUID();
-    std::string guid2 = base::GenerateGUID();
+    std::string guid1 = GenerateGUID();
+    std::string guid2 = GenerateGUID();
     EXPECT_EQ(36U, guid1.length());
     EXPECT_EQ(36U, guid2.length());
     EXPECT_NE(guid1, guid2);
@@ -61,3 +62,5 @@
 #endif
   }
 }
+
+}  // namespace base
diff --git a/base/i18n/bidi_line_iterator.cc b/base/i18n/bidi_line_iterator.cc
index e81a36b..216129e 100644
--- a/base/i18n/bidi_line_iterator.cc
+++ b/base/i18n/bidi_line_iterator.cc
@@ -9,6 +9,25 @@
 namespace base {
 namespace i18n {
 
+namespace {
+  UBiDiLevel GetParagraphLevelForDirection(TextDirection direction) {
+    switch (direction) {
+      case UNKNOWN_DIRECTION:
+        return UBIDI_DEFAULT_LTR;
+        break;
+      case RIGHT_TO_LEFT:
+        return 1;  // Highest RTL level.
+        break;
+      case LEFT_TO_RIGHT:
+        return 0;  // Highest LTR level.
+        break;
+      default:
+        NOTREACHED();
+        return 0;
+    }
+  }
+}  // namespace
+
 BiDiLineIterator::BiDiLineIterator() : bidi_(NULL) {
 }
 
@@ -19,19 +38,14 @@
   }
 }
 
-bool BiDiLineIterator::Open(const string16& text,
-                            bool right_to_left,
-                            bool url) {
+bool BiDiLineIterator::Open(const string16& text, TextDirection direction) {
   DCHECK(!bidi_);
   UErrorCode error = U_ZERO_ERROR;
   bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
   if (U_FAILURE(error))
     return false;
-  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);
+                GetParagraphLevelForDirection(direction), NULL, &error);
   return (U_SUCCESS(error) == TRUE);
 }
 
diff --git a/base/i18n/bidi_line_iterator.h b/base/i18n/bidi_line_iterator.h
index d5a2a07..0bf1ec6 100644
--- a/base/i18n/bidi_line_iterator.h
+++ b/base/i18n/bidi_line_iterator.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/i18n/base_i18n_export.h"
+#include "base/i18n/rtl.h"
 #include "base/strings/string16.h"
 #include "third_party/icu/source/common/unicode/ubidi.h"
 
@@ -23,7 +24,7 @@
 
   // Initializes the bidirectional iterator with the specified text.  Returns
   // whether initialization succeeded.
-  bool Open(const string16& text, bool right_to_left, bool url);
+  bool Open(const string16& text, TextDirection direction);
 
   // Returns the number of visual runs in the text, or zero on error.
   int CountRuns();
diff --git a/base/i18n/break_iterator.cc b/base/i18n/break_iterator.cc
index e2ed667..bc20fff 100644
--- a/base/i18n/break_iterator.cc
+++ b/base/i18n/break_iterator.cc
@@ -138,10 +138,14 @@
 }
 
 bool BreakIterator::IsWord() const {
+  return GetWordBreakStatus() == IS_WORD_BREAK;
+}
+
+BreakIterator::WordBreakStatus BreakIterator::GetWordBreakStatus() 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;
+    return IS_LINE_OR_CHAR_BREAK;
+  return status == UBRK_WORD_NONE ? IS_SKIPPABLE_WORD : IS_WORD_BREAK;
 }
 
 bool BreakIterator::IsEndOfWord(size_t position) const {
diff --git a/base/i18n/break_iterator.h b/base/i18n/break_iterator.h
index 19fdbe0..9dbac7c 100644
--- a/base/i18n/break_iterator.h
+++ b/base/i18n/break_iterator.h
@@ -71,6 +71,19 @@
     RULE_BASED,
   };
 
+  enum WordBreakStatus {
+    // The end of text that the iterator recognizes as word characters.
+    // Non-word characters are things like punctuation and spaces.
+    IS_WORD_BREAK,
+    // Characters that the iterator can skip past, such as punctuation,
+    // whitespace, and, if using RULE_BASED mode, characters from another
+    // character set.
+    IS_SKIPPABLE_WORD,
+    // Only used if not in BREAK_WORD or RULE_BASED mode. This is returned for
+    // newlines, line breaks, and character breaks.
+    IS_LINE_OR_CHAR_BREAK
+  };
+
   // 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.
@@ -101,6 +114,20 @@
   // this distinction doesn't apply and it always returns false.
   bool IsWord() const;
 
+  // Under BREAK_WORD mode:
+  //  - Returns IS_SKIPPABLE_WORD if non-word characters, such as punctuation or
+  //    spaces, are found.
+  //  - Returns IS_WORD_BREAK if the break we just hit is the end of a sequence
+  //    of word characters.
+  // Under RULE_BASED mode:
+  //  - Returns IS_SKIPPABLE_WORD if characters outside the rules' character set
+  //    or non-word characters, such as punctuation or spaces, are found.
+  //  - Returns IS_WORD_BREAK if the break we just hit is the end of a sequence
+  //    of word characters that are in the rules' character set.
+  // Not under BREAK_WORD or RULE_BASED mode:
+  //  - Returns IS_LINE_OR_CHAR_BREAK.
+  BreakIterator::WordBreakStatus GetWordBreakStatus() 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.
diff --git a/base/i18n/break_iterator_unittest.cc b/base/i18n/break_iterator_unittest.cc
index 220a996..c535091 100644
--- a/base/i18n/break_iterator_unittest.cc
+++ b/base/i18n/break_iterator_unittest.cc
@@ -369,5 +369,90 @@
   EXPECT_EQ(StringPiece16(ASCIIToUTF16("string")), iter.GetStringPiece());
 }
 
+// Make sure that when not in RULE_BASED or BREAK_WORD mode we're getting
+// IS_LINE_OR_CHAR_BREAK.
+TEST(BreakIteratorTest, GetWordBreakStatusBreakLine) {
+  // A string containing the English word "foo", followed by two Khmer
+  // characters, the English word "Can", and then two Russian characters and
+  // punctuation.
+  base::string16 text(
+      base::WideToUTF16(L"foo \x1791\x17C1 \nCan \x041C\x0438..."));
+  BreakIterator iter(text, BreakIterator::BREAK_LINE);
+  ASSERT_TRUE(iter.Init());
+
+  EXPECT_TRUE(iter.Advance());
+  // Finds "foo" and the space.
+  EXPECT_EQ(base::UTF8ToUTF16("foo "), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_LINE_OR_CHAR_BREAK);
+  EXPECT_TRUE(iter.Advance());
+  // Finds the Khmer characters, the next space, and the newline.
+  EXPECT_EQ(base::WideToUTF16(L"\x1791\x17C1 \n"), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_LINE_OR_CHAR_BREAK);
+  EXPECT_TRUE(iter.Advance());
+  // Finds "Can" and the space.
+  EXPECT_EQ(base::UTF8ToUTF16("Can "), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_LINE_OR_CHAR_BREAK);
+  EXPECT_TRUE(iter.Advance());
+  // Finds the Russian characters and periods.
+  EXPECT_EQ(base::WideToUTF16(L"\x041C\x0438..."), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_LINE_OR_CHAR_BREAK);
+  EXPECT_FALSE(iter.Advance());
+}
+
+// Make sure that in BREAK_WORD mode we're getting IS_WORD_BREAK and
+// IS_SKIPPABLE_WORD when we should be. IS_WORD_BREAK should be returned when we
+// finish going over non-punctuation characters while IS_SKIPPABLE_WORD should
+// be returned on punctuation and spaces.
+TEST(BreakIteratorTest, GetWordBreakStatusBreakWord) {
+  // A string containing the English word "foo", followed by two Khmer
+  // characters, the English word "Can", and then two Russian characters and
+  // punctuation.
+  base::string16 text(
+      base::WideToUTF16(L"foo \x1791\x17C1 \nCan \x041C\x0438..."));
+  BreakIterator iter(text, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+
+  EXPECT_TRUE(iter.Advance());
+  // Finds "foo".
+  EXPECT_EQ(base::UTF8ToUTF16("foo"), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK);
+  EXPECT_TRUE(iter.Advance());
+  // Finds the space, and the Khmer characters.
+  EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_EQ(base::WideToUTF16(L"\x1791\x17C1"), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK);
+  EXPECT_TRUE(iter.Advance());
+  // Finds the space and the newline.
+  EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_EQ(base::UTF8ToUTF16("\n"), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+  EXPECT_TRUE(iter.Advance());
+  // Finds "Can".
+  EXPECT_EQ(base::UTF8ToUTF16("Can"), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK);
+  EXPECT_TRUE(iter.Advance());
+  // Finds the space and the Russian characters.
+  EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_EQ(base::WideToUTF16(L"\x041C\x0438"), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK);
+  EXPECT_TRUE(iter.Advance());
+  // Finds the trailing periods.
+  EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString());
+  EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+  EXPECT_FALSE(iter.Advance());
+}
+
 }  // namespace i18n
 }  // namespace base
diff --git a/base/i18n/case_conversion.cc b/base/i18n/case_conversion.cc
index 5debc2e..4b62d16 100644
--- a/base/i18n/case_conversion.cc
+++ b/base/i18n/case_conversion.cc
@@ -4,22 +4,84 @@
 
 #include "base/i18n/case_conversion.h"
 
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
 #include "third_party/icu/source/common/unicode/unistr.h"
+#include "third_party/icu/source/common/unicode/ustring.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());
+namespace {
+
+// Provides a uniform interface for upper/lower/folding which take take
+// slightly varying parameters.
+typedef int32_t (*CaseMapperFunction)(UChar* dest, int32_t dest_capacity,
+                                      const UChar* src, int32_t src_length,
+                                      UErrorCode* error);
+
+int32_t ToUpperMapper(UChar* dest, int32_t dest_capacity,
+                      const UChar* src, int32_t src_length,
+                      UErrorCode* error) {
+  // Use default locale.
+  return u_strToUpper(dest, dest_capacity, src, src_length, NULL, error);
 }
 
-string16 ToUpper(const StringPiece16& string) {
-  icu::UnicodeString unicode_string(string.data(), string.size());
-  unicode_string.toUpper();
-  return string16(unicode_string.getBuffer(), unicode_string.length());
+int32_t ToLowerMapper(UChar* dest, int32_t dest_capacity,
+                      const UChar* src, int32_t src_length,
+                      UErrorCode* error) {
+  // Use default locale.
+  return u_strToLower(dest, dest_capacity, src, src_length, NULL, error);
+}
+
+int32_t FoldCaseMapper(UChar* dest, int32_t dest_capacity,
+                       const UChar* src, int32_t src_length,
+                       UErrorCode* error) {
+  return u_strFoldCase(dest, dest_capacity, src, src_length,
+                       U_FOLD_CASE_DEFAULT, error);
+}
+
+// Provides similar functionality as UnicodeString::caseMap but on string16.
+string16 CaseMap(StringPiece16 string, CaseMapperFunction case_mapper) {
+  string16 dest;
+  if (string.empty())
+    return dest;
+
+  // Provide an initial guess that the string length won't change. The typical
+  // strings we use will very rarely change length in this process, so don't
+  // optimize for that case.
+  dest.resize(string.size());
+
+  UErrorCode error;
+  do {
+    error = U_ZERO_ERROR;
+
+    // ICU won't terminate the string if there's not enough room for the null
+    // terminator, but will otherwise. So we don't need to save room for that.
+    // Don't use WriteInto, which assumes null terminators.
+    int32_t new_length = case_mapper(
+        &dest[0], saturated_cast<int32_t>(dest.size()),
+        string.data(), saturated_cast<int32_t>(string.size()),
+        &error);
+    dest.resize(new_length);
+  } while (error == U_BUFFER_OVERFLOW_ERROR);
+  return dest;
+}
+
+}  // namespace
+
+string16 ToLower(StringPiece16 string) {
+  return CaseMap(string, &ToLowerMapper);
+}
+
+string16 ToUpper(StringPiece16 string) {
+  return CaseMap(string, &ToUpperMapper);
+}
+
+string16 FoldCase(StringPiece16 string) {
+  return CaseMap(string, &FoldCaseMapper);
 }
 
 }  // namespace i18n
diff --git a/base/i18n/case_conversion.h b/base/i18n/case_conversion.h
index 5d538cc..0631a80 100644
--- a/base/i18n/case_conversion.h
+++ b/base/i18n/case_conversion.h
@@ -12,11 +12,35 @@
 namespace base {
 namespace i18n {
 
-// Returns the lower case equivalent of string. Uses ICU's default locale.
-BASE_I18N_EXPORT string16 ToLower(const StringPiece16& string);
+// UNICODE CASE-HANDLING ADVICE
+//
+// In English it's always safe to convert to upper-case or lower-case text
+// and get a good answer. But some languages have rules specific to those
+// locales. One example is the Turkish I:
+//   http://www.i18nguy.com/unicode/turkish-i18n.html
+//
+// ToLower/ToUpper use the current ICU locale which will take into account
+// the user language preference. Use this when dealing with user typing.
+//
+// FoldCase canonicalizes to a standardized form independent of the current
+// locale. Use this when comparing general Unicode strings that don't
+// necessarily belong in the user's current locale (like commands, protocol
+// names, other strings from the web) for case-insensitive equality.
+//
+// Note that case conversions will change the length of the string in some
+// not-uncommon cases. Never assume that the output is the same length as
+// the input.
 
-// Returns the upper case equivalent of string. Uses ICU's default locale.
-BASE_I18N_EXPORT string16 ToUpper(const StringPiece16& string);
+// Returns the lower case equivalent of string. Uses ICU's current locale.
+BASE_I18N_EXPORT string16 ToLower(StringPiece16 string);
+
+// Returns the upper case equivalent of string. Uses ICU's current locale.
+BASE_I18N_EXPORT string16 ToUpper(StringPiece16 string);
+
+// Convert the given string to a canonical case, independent of the current
+// locale. For ASCII the canonical form is lower case.
+// See http://unicode.org/faq/casemap_charprop.html#2
+BASE_I18N_EXPORT string16 FoldCase(StringPiece16 string);
 
 }  // namespace i18n
 }  // namespace base
diff --git a/base/i18n/case_conversion_unittest.cc b/base/i18n/case_conversion_unittest.cc
index 38e2c68..ee795bc 100644
--- a/base/i18n/case_conversion_unittest.cc
+++ b/base/i18n/case_conversion_unittest.cc
@@ -3,26 +3,117 @@
 // found in the LICENSE file.
 
 #include "base/i18n/case_conversion.h"
+#include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/icu_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/icu/source/i18n/unicode/usearch.h"
 
 namespace base {
+namespace i18n {
+
 namespace {
 
+const wchar_t kNonASCIIMixed[] =
+    L"\xC4\xD6\xE4\xF6\x20\xCF\xEF\x20\xF7\x25"
+    L"\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07\x1F0F"
+    L"\x20\x1E00\x1E01";
+const wchar_t kNonASCIILower[] =
+    L"\xE4\xF6\xE4\xF6\x20\xEF\xEF"
+    L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07"
+    L"\x1F07\x20\x1E01\x1E01";
+const wchar_t kNonASCIIUpper[] =
+    L"\xC4\xD6\xC4\xD6\x20\xCF\xCF"
+    L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F0F"
+    L"\x1F0F\x20\x1E00\x1E00";
+
+}  // namespace
+
 // Test upper and lower case string conversion.
 TEST(CaseConversionTest, UpperLower) {
-  string16 mixed(ASCIIToUTF16("Text with UPPer & lowER casE."));
+  const string16 mixed(ASCIIToUTF16("Text with UPPer & lowER casE."));
   const string16 expected_lower(ASCIIToUTF16("text with upper & lower case."));
   const string16 expected_upper(ASCIIToUTF16("TEXT WITH UPPER & LOWER CASE."));
 
-  string16 result = base::i18n::ToLower(mixed);
+  string16 result = ToLower(mixed);
   EXPECT_EQ(expected_lower, result);
 
-  result = base::i18n::ToUpper(mixed);
+  result = ToUpper(mixed);
   EXPECT_EQ(expected_upper, result);
 }
 
-// TODO(jshin): More tests are needed, especially with non-ASCII characters.
+TEST(CaseConversionTest, NonASCII) {
+  const string16 mixed(WideToUTF16(kNonASCIIMixed));
+  const string16 expected_lower(WideToUTF16(kNonASCIILower));
+  const string16 expected_upper(WideToUTF16(kNonASCIIUpper));
 
-}  // namespace
+  string16 result = ToLower(mixed);
+  EXPECT_EQ(expected_lower, result);
+
+  result = ToUpper(mixed);
+  EXPECT_EQ(expected_upper, result);
+}
+
+TEST(CaseConversionTest, TurkishLocaleConversion) {
+  const string16 mixed(WideToUTF16(L"\x49\x131"));
+  const string16 expected_lower(WideToUTF16(L"\x69\x131"));
+  const string16 expected_upper(WideToUTF16(L"\x49\x49"));
+
+  test::ScopedRestoreICUDefaultLocale restore_locale;
+  i18n::SetICUDefaultLocale("en_US");
+
+  string16 result = ToLower(mixed);
+  EXPECT_EQ(expected_lower, result);
+
+  result = ToUpper(mixed);
+  EXPECT_EQ(expected_upper, result);
+
+  i18n::SetICUDefaultLocale("tr");
+
+  const string16 expected_lower_turkish(WideToUTF16(L"\x131\x131"));
+  const string16 expected_upper_turkish(WideToUTF16(L"\x49\x49"));
+
+  result = ToLower(mixed);
+  EXPECT_EQ(expected_lower_turkish, result);
+
+  result = ToUpper(mixed);
+  EXPECT_EQ(expected_upper_turkish, result);
+}
+
+TEST(CaseConversionTest, FoldCase) {
+  // Simple ASCII, should lower-case.
+  EXPECT_EQ(ASCIIToUTF16("hello, world"),
+            FoldCase(ASCIIToUTF16("Hello, World")));
+
+  // Non-ASCII cases from above. They should all fold to the same result.
+  EXPECT_EQ(FoldCase(WideToUTF16(kNonASCIIMixed)),
+            FoldCase(WideToUTF16(kNonASCIILower)));
+  EXPECT_EQ(FoldCase(WideToUTF16(kNonASCIIMixed)),
+            FoldCase(WideToUTF16(kNonASCIIUpper)));
+
+  // Turkish cases from above. This is the lower-case expected result from the
+  // US locale. It should be the same even when the current locale is Turkish.
+  const string16 turkish(WideToUTF16(L"\x49\x131"));
+  const string16 turkish_expected(WideToUTF16(L"\x69\x131"));
+
+  test::ScopedRestoreICUDefaultLocale restore_locale;
+  i18n::SetICUDefaultLocale("en_US");
+  EXPECT_EQ(turkish_expected, FoldCase(turkish));
+
+  i18n::SetICUDefaultLocale("tr");
+  EXPECT_EQ(turkish_expected, FoldCase(turkish));
+
+  // Test a case that gets bigger when processed.
+  // U+130 = LATIN CAPITAL LETTER I WITH DOT ABOVE gets folded to a lower case
+  // "i" followed by U+307 COMBINING DOT ABOVE.
+  EXPECT_EQ(WideToUTF16(L"i\u0307j"), FoldCase(WideToUTF16(L"\u0130j")));
+
+  // U+00DF (SHARP S) and U+1E9E (CAPIRAL SHARP S) are both folded to "ss".
+  EXPECT_EQ(ASCIIToUTF16("ssss"), FoldCase(WideToUTF16(L"\u00DF\u1E9E")));
+}
+
+}  // namespace i18n
 }  // namespace base
+
+
+
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
index a9f0b12..e3afc04 100644
--- a/base/i18n/icu_util.cc
+++ b/base/i18n/icu_util.cc
@@ -23,6 +23,10 @@
 #include "third_party/icu/source/i18n/unicode/timezone.h"
 #endif
 
+#if defined(OS_ANDROID)
+#include "base/android/apk_assets.h"
+#endif
+
 #if defined(OS_MACOSX)
 #include "base/mac/foundation_util.h"
 #endif
@@ -34,11 +38,6 @@
 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)
@@ -47,44 +46,164 @@
 #endif
 
 namespace {
-
+#if !defined(OS_NACL)
 #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;
+bool g_called_once = false;
+#endif  // !defined(NDEBUG)
+
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+// 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 defined(OS_ANDROID)
+const char kAndroidAssetsIcuDataFileName[] = "assets/icudtl.dat";
 #endif
+
+// File handle intentionally never closed. Not using File here because its
+// Windows implementation guards against two instances owning the same
+// PlatformFile (which we allow since we know it is never freed).
+const PlatformFile kInvalidPlatformFile =
+#if defined(OS_WIN)
+    INVALID_HANDLE_VALUE;
+#else
+    -1;
+#endif
+PlatformFile g_icudtl_pf = kInvalidPlatformFile;
+MemoryMappedFile* g_icudtl_mapped_file = nullptr;
+MemoryMappedFile::Region g_icudtl_region;
+
+void LazyInitIcuDataFile() {
+  if (g_icudtl_pf != kInvalidPlatformFile) {
+    return;
+  }
+#if defined(OS_ANDROID)
+  int fd = base::android::OpenApkAsset(kAndroidAssetsIcuDataFileName,
+                                       &g_icudtl_region);
+  g_icudtl_pf = fd;
+  if (fd != -1) {
+    return;
+  }
+// For unit tests, data file is located on disk, so try there as a fallback.
+#endif  // defined(OS_ANDROID)
+#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;
+  }
+#endif  // !defined(OS_MACOSX)
+  File file(data_path, File::FLAG_OPEN | File::FLAG_READ);
+  if (file.IsValid()) {
+    g_icudtl_pf = file.TakePlatformFile();
+    g_icudtl_region = MemoryMappedFile::Region::kWholeFile;
+  }
 }
 
+bool InitializeICUWithFileDescriptorInternal(
+    PlatformFile data_fd,
+    const MemoryMappedFile::Region& data_region) {
+  // This can be called multiple times in tests.
+  if (g_icudtl_mapped_file) {
+    return true;
+  }
+  if (data_fd == kInvalidPlatformFile) {
+    LOG(ERROR) << "Invalid file descriptor to ICU data received.";
+    return false;
+  }
+
+  scoped_ptr<MemoryMappedFile> icudtl_mapped_file(new MemoryMappedFile());
+  if (!icudtl_mapped_file->Initialize(File(data_fd), data_region)) {
+    LOG(ERROR) << "Couldn't mmap icu data file";
+    return false;
+  }
+  g_icudtl_mapped_file = icudtl_mapped_file.release();
+
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(const_cast<uint8*>(g_icudtl_mapped_file->data()), &err);
+  return err == U_ZERO_ERROR;
+}
+#endif  // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#endif  // !defined(OS_NACL)
+
+}  // namespace
+
 #if !defined(OS_NACL)
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#if defined(OS_ANDROID)
 bool InitializeICUWithFileDescriptor(
     PlatformFile data_fd,
-    MemoryMappedFile::Region data_region) {
+    const MemoryMappedFile::Region& data_region) {
+#if !defined(NDEBUG)
+  DCHECK(!g_check_called_once || !g_called_once);
+  g_called_once = true;
+#endif
+  return InitializeICUWithFileDescriptorInternal(data_fd, data_region);
+}
+
+PlatformFile GetIcuDataFileHandle(MemoryMappedFile::Region* out_region) {
+  CHECK_NE(g_icudtl_pf, kInvalidPlatformFile);
+  *out_region = g_icudtl_region;
+  return g_icudtl_pf;
+}
+#endif
+
+const uint8* GetRawIcuMemory() {
+  CHECK(g_icudtl_mapped_file);
+  return g_icudtl_mapped_file->data();
+}
+
+bool InitializeICUFromRawMemory(const uint8* raw_memory) {
+#if !defined(COMPONENT_BUILD)
 #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);
+  udata_setCommonData(const_cast<uint8*>(raw_memory), &err);
   return err == U_ZERO_ERROR;
-#endif // ICU_UTIL_DATA_FILE
+#else
+  return true;
+#endif
 }
 
+#endif  // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
 
 bool InitializeICU() {
 #if !defined(NDEBUG)
@@ -123,60 +242,9 @@
   // 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);
+  LazyInitIcuDataFile();
+  result =
+      InitializeICUWithFileDescriptorInternal(g_icudtl_pf, g_icudtl_region);
 #if defined(OS_WIN)
   CHECK(result);  // TODO(scottmg): http://crbug.com/445616
 #endif
@@ -193,10 +261,10 @@
 #endif
   return result;
 }
-#endif
+#endif  // !defined(OS_NACL)
 
 void AllowMultipleInitializeCallsForTesting() {
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) && !defined(OS_NACL)
   g_check_called_once = false;
 #endif
 }
diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h
index 65de0ad..ec24426 100644
--- a/base/i18n/icu_util.h
+++ b/base/i18n/icu_util.h
@@ -12,20 +12,46 @@
 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.
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#if defined(OS_ANDROID)
+// Returns the PlatformFile and Region that was initialized by InitializeICU().
+// Use with InitializeICUWithFileDescriptor().
+BASE_I18N_EXPORT PlatformFile GetIcuDataFileHandle(
+    MemoryMappedFile::Region* out_region);
+
+// Android uses 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);
+    const MemoryMappedFile::Region& data_region);
 #endif
 
+// Returns a void pointer to the memory mapped ICU data file.
+//
+// There are cases on Android where we would be unsafely reusing a file
+// descriptor within the same process when initializing two copies of ICU from
+// different binaries in the same address space. This returns an unowned
+// pointer to the memory mapped icu data file; consumers copies of base must
+// not outlive the copy of base that owns the memory mapped file.
+BASE_I18N_EXPORT const uint8* GetRawIcuMemory();
+
+// Initializes ICU memory
+//
+// This does nothing in component builds; this initialization should only be
+// done in cases where there could be two copies of base in a single process in
+// non-component builds. (The big example is mojo: the shell will have a copy
+// of base linked in, and the majority of mojo applications will have base
+// linked in but in non-component builds, these will be separate copies of
+// base.)
+BASE_I18N_EXPORT bool InitializeICUFromRawMemory(const uint8* raw_memory);
+#endif  // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#endif  // !defined(OS_NACL)
+
 // In a test binary, the call above might occur twice.
 BASE_I18N_EXPORT void AllowMultipleInitializeCallsForTesting();
 
diff --git a/base/i18n/message_formatter.cc b/base/i18n/message_formatter.cc
new file mode 100644
index 0000000..702e51b
--- /dev/null
+++ b/base/i18n/message_formatter.cc
@@ -0,0 +1,141 @@
+// Copyright 2015 The Chromium Authors. All 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/message_formatter.h"
+
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/time/time.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
+#include "third_party/icu/source/common/unicode/utypes.h"
+#include "third_party/icu/source/i18n/unicode/fmtable.h"
+#include "third_party/icu/source/i18n/unicode/msgfmt.h"
+
+using icu::UnicodeString;
+
+namespace base {
+namespace i18n {
+namespace {
+UnicodeString UnicodeStringFromStringPiece(StringPiece str) {
+  return UnicodeString::fromUTF8(
+      icu::StringPiece(str.data(), base::checked_cast<int32_t>(str.size())));
+}
+}  // anonymous namespace
+
+namespace internal {
+MessageArg::MessageArg() : formattable(nullptr) {}
+
+MessageArg::MessageArg(const char* s)
+    : formattable(new icu::Formattable(UnicodeStringFromStringPiece(s))) {}
+
+MessageArg::MessageArg(StringPiece s)
+    : formattable(new icu::Formattable(UnicodeStringFromStringPiece(s))) {}
+
+MessageArg::MessageArg(const std::string& s)
+    : formattable(new icu::Formattable(UnicodeString::fromUTF8(s))) {}
+
+MessageArg::MessageArg(const string16& s)
+    : formattable(new icu::Formattable(UnicodeString(s.data(), s.size()))) {}
+
+MessageArg::MessageArg(int i) : formattable(new icu::Formattable(i)) {}
+
+MessageArg::MessageArg(int64_t i) : formattable(new icu::Formattable(i)) {}
+
+MessageArg::MessageArg(double d) : formattable(new icu::Formattable(d)) {}
+
+MessageArg::MessageArg(const Time& t)
+    : formattable(new icu::Formattable(static_cast<UDate>(t.ToJsTime()))) {}
+
+MessageArg::~MessageArg() {}
+
+// Tests if this argument has a value, and if so increments *count.
+bool MessageArg::has_value(int *count) const {
+  if (formattable == nullptr)
+    return false;
+
+  ++*count;
+  return true;
+}
+
+}  // namespace internal
+
+string16 MessageFormatter::FormatWithNumberedArgs(
+    StringPiece16 msg,
+    const internal::MessageArg& arg0,
+    const internal::MessageArg& arg1,
+    const internal::MessageArg& arg2,
+    const internal::MessageArg& arg3,
+    const internal::MessageArg& arg4,
+    const internal::MessageArg& arg5,
+    const internal::MessageArg& arg6) {
+  int32_t args_count = 0;
+  icu::Formattable args[] = {
+      arg0.has_value(&args_count) ? *arg0.formattable : icu::Formattable(),
+      arg1.has_value(&args_count) ? *arg1.formattable : icu::Formattable(),
+      arg2.has_value(&args_count) ? *arg2.formattable : icu::Formattable(),
+      arg3.has_value(&args_count) ? *arg3.formattable : icu::Formattable(),
+      arg4.has_value(&args_count) ? *arg4.formattable : icu::Formattable(),
+      arg5.has_value(&args_count) ? *arg5.formattable : icu::Formattable(),
+      arg6.has_value(&args_count) ? *arg6.formattable : icu::Formattable(),
+  };
+
+  UnicodeString msg_string(msg.data(), msg.size());
+  UErrorCode error = U_ZERO_ERROR;
+  icu::MessageFormat format(msg_string,  error);
+  icu::UnicodeString formatted;
+  icu::FieldPosition ignore(icu::FieldPosition::DONT_CARE);
+  format.format(args, args_count, formatted, ignore, error);
+  if (U_FAILURE(error)) {
+    LOG(ERROR) << "MessageFormat(" << msg.as_string() << ") failed with "
+               << u_errorName(error);
+    return string16();
+  }
+  return string16(formatted.getBuffer(), formatted.length());
+}
+
+string16 MessageFormatter::FormatWithNamedArgs(
+    StringPiece16 msg,
+    StringPiece name0, const internal::MessageArg& arg0,
+    StringPiece name1, const internal::MessageArg& arg1,
+    StringPiece name2, const internal::MessageArg& arg2,
+    StringPiece name3, const internal::MessageArg& arg3,
+    StringPiece name4, const internal::MessageArg& arg4,
+    StringPiece name5, const internal::MessageArg& arg5,
+    StringPiece name6, const internal::MessageArg& arg6) {
+  icu::UnicodeString names[] = {
+      UnicodeStringFromStringPiece(name0),
+      UnicodeStringFromStringPiece(name1),
+      UnicodeStringFromStringPiece(name2),
+      UnicodeStringFromStringPiece(name3),
+      UnicodeStringFromStringPiece(name4),
+      UnicodeStringFromStringPiece(name5),
+      UnicodeStringFromStringPiece(name6),
+  };
+  int32_t args_count = 0;
+  icu::Formattable args[] = {
+      arg0.has_value(&args_count) ? *arg0.formattable : icu::Formattable(),
+      arg1.has_value(&args_count) ? *arg1.formattable : icu::Formattable(),
+      arg2.has_value(&args_count) ? *arg2.formattable : icu::Formattable(),
+      arg3.has_value(&args_count) ? *arg3.formattable : icu::Formattable(),
+      arg4.has_value(&args_count) ? *arg4.formattable : icu::Formattable(),
+      arg5.has_value(&args_count) ? *arg5.formattable : icu::Formattable(),
+      arg6.has_value(&args_count) ? *arg6.formattable : icu::Formattable(),
+  };
+
+  UnicodeString msg_string(msg.data(), msg.size());
+  UErrorCode error = U_ZERO_ERROR;
+  icu::MessageFormat format(msg_string, error);
+
+  icu::UnicodeString formatted;
+  format.format(names, args, args_count, formatted, error);
+  if (U_FAILURE(error)) {
+    LOG(ERROR) << "MessageFormat(" << msg.as_string() << ") failed with "
+               << u_errorName(error);
+    return string16();
+  }
+  return string16(formatted.getBuffer(), formatted.length());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/message_formatter.h b/base/i18n/message_formatter.h
new file mode 100644
index 0000000..bcdc3bc
--- /dev/null
+++ b/base/i18n/message_formatter.h
@@ -0,0 +1,111 @@
+// Copyright 2015 The Chromium Authors. All 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_MESSAGE_FORMATTER_H_
+#define BASE_I18N_MESSAGE_FORMATTER_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "third_party/icu/source/common/unicode/uversion.h"
+
+U_NAMESPACE_BEGIN
+class Formattable;
+U_NAMESPACE_END
+
+namespace base {
+
+class Time;
+
+namespace i18n {
+
+class MessageFormatter;
+
+namespace internal {
+
+class BASE_I18N_EXPORT MessageArg {
+ public:
+  MessageArg(const char* s);
+  MessageArg(StringPiece s);
+  MessageArg(const std::string& s);
+  MessageArg(const string16& s);
+  MessageArg(int i);
+  MessageArg(int64_t i);
+  MessageArg(double d);
+  MessageArg(const Time& t);
+  ~MessageArg();
+
+ private:
+  friend class base::i18n::MessageFormatter;
+  MessageArg();
+  // Tests if this argument has a value, and if so increments *count.
+  bool has_value(int* count) const;
+  scoped_ptr<icu::Formattable> formattable;
+  DISALLOW_COPY_AND_ASSIGN(MessageArg);
+};
+
+}  // namespace internal
+
+// Message Formatter with the ICU message format syntax support.
+// It can format strings (UTF-8 and UTF-16), numbers and base::Time with
+// plural, gender and other 'selectors' support. This is handy if you
+// have multiple parameters of differnt types and some of them require
+// plural or gender/selector support.
+//
+// To use this API for locale-sensitive formatting, retrieve a 'message
+// template' in the ICU message format from a message bundle (e.g. with
+// l10n_util::GetStringUTF16()) and pass it to FormatWith{Named,Numbered}Args.
+//
+// MessageFormat specs:
+//   http://icu-project.org/apiref/icu4j/com/ibm/icu/text/MessageFormat.html
+//   http://icu-project.org/apiref/icu4c/classicu_1_1DecimalFormat.html#details
+// Examples:
+//   http://userguide.icu-project.org/formatparse/messages
+//   message_formatter_unittest.cc
+//   go/plurals inside Google.
+//   TODO(jshin): Document this API at sites.chromium.org and add a reference
+//   here.
+
+class BASE_I18N_EXPORT MessageFormatter {
+ public:
+  static string16 FormatWithNamedArgs(
+      StringPiece16 msg,
+      StringPiece name0 = StringPiece(),
+      const internal::MessageArg& arg0 = internal::MessageArg(),
+      StringPiece name1 = StringPiece(),
+      const internal::MessageArg& arg1 = internal::MessageArg(),
+      StringPiece name2 = StringPiece(),
+      const internal::MessageArg& arg2 = internal::MessageArg(),
+      StringPiece name3 = StringPiece(),
+      const internal::MessageArg& arg3 = internal::MessageArg(),
+      StringPiece name4 = StringPiece(),
+      const internal::MessageArg& arg4 = internal::MessageArg(),
+      StringPiece name5 = StringPiece(),
+      const internal::MessageArg& arg5 = internal::MessageArg(),
+      StringPiece name6 = StringPiece(),
+      const internal::MessageArg& arg6 = internal::MessageArg());
+
+  static string16 FormatWithNumberedArgs(
+      StringPiece16 msg,
+      const internal::MessageArg& arg0 = internal::MessageArg(),
+      const internal::MessageArg& arg1 = internal::MessageArg(),
+      const internal::MessageArg& arg2 = internal::MessageArg(),
+      const internal::MessageArg& arg3 = internal::MessageArg(),
+      const internal::MessageArg& arg4 = internal::MessageArg(),
+      const internal::MessageArg& arg5 = internal::MessageArg(),
+      const internal::MessageArg& arg6 = internal::MessageArg());
+
+ private:
+  MessageFormatter() {}
+  DISALLOW_COPY_AND_ASSIGN(MessageFormatter);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_MESSAGE_FORMATTER_H_
diff --git a/base/i18n/message_formatter_unittest.cc b/base/i18n/message_formatter_unittest.cc
new file mode 100644
index 0000000..85e2e17
--- /dev/null
+++ b/base/i18n/message_formatter_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 "base/i18n/message_formatter.h"
+
+#include "base/i18n/rtl.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.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/unistr.h"
+#include "third_party/icu/source/i18n/unicode/datefmt.h"
+#include "third_party/icu/source/i18n/unicode/msgfmt.h"
+
+typedef testing::Test MessageFormatterTest;
+
+namespace base {
+namespace i18n {
+
+class MessageFormatterTest : public testing::Test {
+ protected:
+  MessageFormatterTest() {
+    original_locale_ = GetConfiguredLocale();
+    SetICUDefaultLocale("en-US");
+  }
+  ~MessageFormatterTest() override {
+    SetICUDefaultLocale(original_locale_);
+  }
+
+ private:
+  std::string original_locale_;
+};
+
+namespace {
+
+void AppendFormattedDateTime(const scoped_ptr<icu::DateFormat>& df,
+                             const Time& now, std::string* result) {
+  icu::UnicodeString formatted;
+  df->format(static_cast<UDate>(now.ToJsTime()), formatted).
+      toUTF8String(*result);
+}
+
+}  // namespace
+
+TEST_F(MessageFormatterTest, PluralNamedArgs) {
+  const string16 pattern = ASCIIToUTF16(
+      "{num_people, plural, "
+      "=0 {I met nobody in {place}.}"
+      "=1 {I met a person in {place}.}"
+      "other {I met # people in {place}.}}");
+
+  std::string result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
+      pattern, "num_people", 0, "place", "Paris"));
+  EXPECT_EQ("I met nobody in Paris.", result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
+      pattern, "num_people", 1, "place", "Paris"));
+  EXPECT_EQ("I met a person in Paris.", result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
+      pattern, "num_people", 5, "place", "Paris"));
+  EXPECT_EQ("I met 5 people in Paris.", result);
+}
+
+TEST_F(MessageFormatterTest, PluralNamedArgsWithOffset) {
+  const string16 pattern = ASCIIToUTF16(
+      "{num_people, plural, offset:1 "
+      "=0 {I met nobody in {place}.}"
+      "=1 {I met {person} in {place}.}"
+      "=2 {I met {person} and one other person in {place}.}"
+      "=13 {I met {person} and a dozen other people in {place}.}"
+      "other {I met {person} and # other people in {place}.}}");
+
+  std::string result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
+      pattern, "num_people", 0, "place", "Paris"));
+  EXPECT_EQ("I met nobody in Paris.", result);
+  // {person} is ignored if {num_people} is 0.
+  result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
+      pattern, "num_people", 0, "place", "Paris", "person", "Peter"));
+  EXPECT_EQ("I met nobody in Paris.", result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
+      pattern, "num_people", 1, "place", "Paris", "person", "Peter"));
+  EXPECT_EQ("I met Peter in Paris.", result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
+      pattern, "num_people", 2, "place", "Paris", "person", "Peter"));
+  EXPECT_EQ("I met Peter and one other person in Paris.", result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
+      pattern, "num_people", 13, "place", "Paris", "person", "Peter"));
+  EXPECT_EQ("I met Peter and a dozen other people in Paris.", result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs(
+      pattern, "num_people", 50, "place", "Paris", "person", "Peter"));
+  EXPECT_EQ("I met Peter and 49 other people in Paris.", result);
+}
+
+TEST_F(MessageFormatterTest, PluralNumberedArgs) {
+  const string16 pattern = ASCIIToUTF16(
+      "{1, plural, "
+      "=1 {The cert for {0} expired yesterday.}"
+      "=7 {The cert for {0} expired a week ago.}"
+      "other {The cert for {0} expired # days ago.}}");
+
+  std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
+      pattern, "example.com", 1));
+  EXPECT_EQ("The cert for example.com expired yesterday.", result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
+      pattern, "example.com", 7));
+  EXPECT_EQ("The cert for example.com expired a week ago.", result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
+      pattern, "example.com", 15));
+  EXPECT_EQ("The cert for example.com expired 15 days ago.", result);
+}
+
+TEST_F(MessageFormatterTest, PluralNumberedArgsWithDate) {
+  const string16 pattern = ASCIIToUTF16(
+      "{1, plural, "
+      "=1 {The cert for {0} expired yesterday. Today is {2,date,full}}"
+      "other {The cert for {0} expired # days ago. Today is {2,date,full}}}");
+
+  base::Time now = base::Time::Now();
+  using icu::DateFormat;
+  scoped_ptr<DateFormat> df(DateFormat::createDateInstance(DateFormat::FULL));
+  std::string second_sentence = " Today is ";
+  AppendFormattedDateTime(df, now, &second_sentence);
+
+  std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
+      pattern, "example.com", 1, now));
+  EXPECT_EQ("The cert for example.com expired yesterday." + second_sentence,
+            result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
+      pattern, "example.com", 15, now));
+  EXPECT_EQ("The cert for example.com expired 15 days ago." + second_sentence,
+            result);
+}
+
+TEST_F(MessageFormatterTest, DateTimeAndNumber) {
+  // Note that using 'mph' for all locales is not a good i18n practice.
+  const string16 pattern = ASCIIToUTF16(
+      "At {0,time, short} on {0,date, medium}, "
+      "there was {1} at building {2,number,integer}. "
+      "The speed of the wind was {3,number,###.#} mph.");
+
+  using icu::DateFormat;
+  scoped_ptr<DateFormat> tf(DateFormat::createTimeInstance(DateFormat::SHORT));
+  scoped_ptr<DateFormat> df(DateFormat::createDateInstance(DateFormat::MEDIUM));
+
+  base::Time now = base::Time::Now();
+  std::string expected = "At ";
+  AppendFormattedDateTime(tf, now, &expected);
+  expected.append(" on ");
+  AppendFormattedDateTime(df, now, &expected);
+  expected.append(", there was an explosion at building 3. "
+                  "The speed of the wind was 37.4 mph.");
+
+  EXPECT_EQ(expected, UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
+      pattern, now, "an explosion", 3, 37.413)));
+}
+
+TEST_F(MessageFormatterTest, SelectorSingleOrMultiple) {
+  const string16 pattern = ASCIIToUTF16(
+      "{0, select,"
+      "single {Select a file to upload.}"
+      "multiple {Select files to upload.}"
+      "other {UNUSED}}");
+
+  std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
+      pattern, "single"));
+  EXPECT_EQ("Select a file to upload.", result);
+  result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
+      pattern, "multiple"));
+  EXPECT_EQ("Select files to upload.", result);
+
+  // fallback if a parameter is not selectors specified in the message pattern.
+  result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs(
+      pattern, "foobar"));
+  EXPECT_EQ("UNUSED", result);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/number_formatting_unittest.cc b/base/i18n/number_formatting_unittest.cc
index 3b0718d..dc6de2b 100644
--- a/base/i18n/number_formatting_unittest.cc
+++ b/base/i18n/number_formatting_unittest.cc
@@ -7,7 +7,9 @@
 #include "base/i18n/number_formatting.h"
 #include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/icu_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/icu/source/i18n/unicode/usearch.h"
 
 namespace base {
 namespace {
@@ -27,6 +29,8 @@
     {-42, "-42", "-42"},
   };
 
+  test::ScopedRestoreICUDefaultLocale restore_locale;
+
   for (size_t i = 0; i < arraysize(cases); ++i) {
     i18n::SetICUDefaultLocale("en");
     testing::ResetFormatters();
@@ -72,6 +76,7 @@
     {-42.7, 3, "-42.700", "-42,700"},
   };
 
+  test::ScopedRestoreICUDefaultLocale restore_locale;
   for (size_t i = 0; i < arraysize(cases); ++i) {
     i18n::SetICUDefaultLocale("en");
     testing::ResetFormatters();
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
index 1cccae2..ac9589c 100644
--- a/base/i18n/rtl.cc
+++ b/base/i18n/rtl.cc
@@ -4,8 +4,11 @@
 
 #include "base/i18n/rtl.h"
 
+#include <algorithm>
+
 #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/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -14,6 +17,10 @@
 #include "third_party/icu/source/common/unicode/uscript.h"
 #include "third_party/icu/source/i18n/unicode/coll.h"
 
+#if defined(OS_IOS)
+#include "base/ios/ios_util.h"
+#endif
+
 namespace {
 
 // Extract language, country and variant, but ignore keywords.  For example,
@@ -31,11 +38,8 @@
     result += country;
   }
 
-  if (variant != NULL && *variant != '\0') {
-    std::string variant_str(variant);
-    base::StringToLowerASCII(&variant_str);
-    result += '@' + variant_str;
-  }
+  if (variant != NULL && *variant != '\0')
+    result += '@' + base::ToLowerASCII(variant);
 
   return result;
 }
@@ -125,12 +129,38 @@
 bool ICUIsRTL() {
   if (g_icu_text_direction == UNKNOWN_DIRECTION) {
     const icu::Locale& locale = icu::Locale::getDefault();
-    g_icu_text_direction = GetTextDirectionForLocale(locale.getName());
+    g_icu_text_direction = GetTextDirectionForLocaleInStartUp(locale.getName());
   }
   return g_icu_text_direction == RIGHT_TO_LEFT;
 }
 
+TextDirection GetTextDirectionForLocaleInStartUp(const char* locale_name) {
+// On iOS, check for RTL forcing.
+#if defined(OS_IOS)
+  if (ios::IsInForcedRTL())
+    return RIGHT_TO_LEFT;
+#endif
+
+  // This list needs to be updated in alphabetical order if we add more RTL
+  // locales.
+  static const char* kRTLLanguageCodes[] = {"ar", "fa", "he", "iw", "ur"};
+  std::vector<StringPiece> locale_split =
+      SplitStringPiece(locale_name, "-_", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  const StringPiece& language_code = locale_split[0];
+  if (std::binary_search(kRTLLanguageCodes,
+                         kRTLLanguageCodes + arraysize(kRTLLanguageCodes),
+                         language_code))
+    return RIGHT_TO_LEFT;
+  return LEFT_TO_RIGHT;
+}
+
 TextDirection GetTextDirectionForLocale(const char* locale_name) {
+  // On iOS, check for RTL forcing.
+#if defined(OS_IOS)
+  if (ios::IsInForcedRTL())
+    return RIGHT_TO_LEFT;
+#endif
+
   UErrorCode status = U_ZERO_ERROR;
   ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status);
   DCHECK(U_SUCCESS(status));
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
index 9b9a0dc..bba93ce 100644
--- a/base/i18n/rtl.h
+++ b/base/i18n/rtl.h
@@ -61,6 +61,12 @@
 BASE_I18N_EXPORT bool ICUIsRTL();
 
 // Returns the text direction for |locale_name|.
+// As a startup optimization, this method checks the locale against a list of
+// Chrome-supported RTL locales.
+BASE_I18N_EXPORT TextDirection
+GetTextDirectionForLocaleInStartUp(const char* locale_name);
+
+// Returns the text direction for |locale_name|.
 BASE_I18N_EXPORT TextDirection GetTextDirectionForLocale(
     const char* locale_name);
 
diff --git a/base/i18n/rtl_unittest.cc b/base/i18n/rtl_unittest.cc
index 87ac87d..6deaf34 100644
--- a/base/i18n/rtl_unittest.cc
+++ b/base/i18n/rtl_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/icu_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "third_party/icu/source/i18n/unicode/usearch.h"
@@ -305,6 +306,7 @@
 
   const bool was_rtl = IsRTL();
 
+  test::ScopedRestoreICUDefaultLocale restore_locale;
   for (size_t i = 0; i < 2; ++i) {
     // Toggle the application default text direction (to try each direction).
     SetRTL(!IsRTL());
@@ -352,6 +354,7 @@
 
   const bool was_rtl = IsRTL();
 
+  test::ScopedRestoreICUDefaultLocale restore_locale;
   for (size_t i = 0; i < 2; ++i) {
     // Toggle the application default text direction (to try each direction).
     SetRTL(!IsRTL());
@@ -399,6 +402,28 @@
   EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ja"));
 }
 
+TEST_F(RTLTest, GetTextDirectionForLocaleInStartUp) {
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("ar"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("ar_EG"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("he"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("he_IL"));
+  // iw is an obsolete code for Hebrew.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("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, GetTextDirectionForLocaleInStartUp("fa"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocaleInStartUp("ur"));
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("en"));
+  // Chinese in China with '-'.
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("zh-CN"));
+  // Filipino : 3-letter code
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("fil"));
+  // Russian
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("ru"));
+  // Japanese that uses multiple scripts
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocaleInStartUp("ja"));
+}
+
 TEST_F(RTLTest, UnadjustStringForLocaleDirection) {
   // These test strings are borrowed from WrapPathWithLTRFormatting
   const wchar_t* cases[] = {
@@ -416,6 +441,7 @@
 
   const bool was_rtl = IsRTL();
 
+  test::ScopedRestoreICUDefaultLocale restore_locale;
   for (size_t i = 0; i < 2; ++i) {
     // Toggle the application default text direction (to try each direction).
     SetRTL(!IsRTL());
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc
index 15b34a3..5512111 100644
--- a/base/i18n/time_formatting.cc
+++ b/base/i18n/time_formatting.cc
@@ -45,6 +45,26 @@
                   static_cast<size_t>(time_string.length()));
 }
 
+icu::SimpleDateFormat CreateSimpleDateFormatter(const char* pattern) {
+  // 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));
+  icu::UnicodeString generated_pattern =
+      generator->getBestPattern(icu::UnicodeString(pattern), status);
+  DCHECK(U_SUCCESS(status));
+
+  // Then, format the time using the generated pattern.
+  icu::SimpleDateFormat formatter(generated_pattern, status);
+  DCHECK(U_SUCCESS(status));
+
+  return formatter;
+}
+
 }  // namespace
 
 string16 TimeFormatTimeOfDay(const Time& time) {
@@ -55,6 +75,11 @@
   return TimeFormat(formatter.get(), time);
 }
 
+string16 TimeFormatTimeOfDayWithMilliseconds(const Time& time) {
+  icu::SimpleDateFormat formatter = CreateSimpleDateFormatter("HmsSSS");
+  return TimeFormatWithoutAmPm(&formatter, time);
+}
+
 string16 TimeFormatTimeOfDayWithHourClockType(const Time& time,
                                               HourClockType type,
                                               AmPmClockType ampm) {
@@ -65,22 +90,9 @@
     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));
+  icu::SimpleDateFormat formatter = CreateSimpleDateFormatter(base_pattern);
 
-  // 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 {
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h
index 2053c0b..df91f41 100644
--- a/base/i18n/time_formatting.h
+++ b/base/i18n/time_formatting.h
@@ -30,6 +30,10 @@
 // Returns the time of day, e.g., "3:07 PM".
 BASE_I18N_EXPORT string16 TimeFormatTimeOfDay(const Time& time);
 
+// Returns the time of day in 24-hour clock format with millisecond accuracy,
+// e.g., "15:07:30.568"
+BASE_I18N_EXPORT string16 TimeFormatTimeOfDayWithMilliseconds(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).
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc
index df0c1ed..e64acf1 100644
--- a/base/i18n/time_formatting_unittest.cc
+++ b/base/i18n/time_formatting_unittest.cc
@@ -7,11 +7,13 @@
 #include "base/i18n/rtl.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/icu_test_util.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"
+#include "third_party/icu/source/i18n/unicode/tzfmt.h"
 
 namespace base {
 namespace {
@@ -21,25 +23,37 @@
   15, 42, 7, 0    // 15:42:07.000
 };
 
-base::string16 GetShortTimeZone() {
+// Returns difference between the local time and GMT formatted as string.
+// This function gets |time| because the difference depends on time,
+// see https://en.wikipedia.org/wiki/Daylight_saving_time for details.
+base::string16 GetShortTimeZone(const Time& time) {
+  UErrorCode status = U_ZERO_ERROR;
   scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+  scoped_ptr<icu::TimeZoneFormat> zone_formatter(
+      icu::TimeZoneFormat::createInstance(icu::Locale::getDefault(), status));
+  EXPECT_TRUE(U_SUCCESS(status));
   icu::UnicodeString name;
-  zone->getDisplayName(true, icu::TimeZone::SHORT, name);
+  zone_formatter->format(UTZFMT_STYLE_SPECIFIC_SHORT, *zone,
+                         static_cast<UDate>(time.ToDoubleT() * 1000),
+                         name, nullptr);
   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.
+  test::ScopedRestoreICUDefaultLocale restore_locale;
   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"));
+  string16 clock24h_millis(ASCIIToUTF16("15:42:07.000"));
 
   // The default is 12h clock.
   EXPECT_EQ(clock12h_pm, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(clock24h_millis, TimeFormatTimeOfDayWithMilliseconds(time));
   EXPECT_EQ(k12HourClock, GetHourClockType());
   // k{Keep,Drop}AmPm should not affect for 24h clock.
   EXPECT_EQ(clock24h,
@@ -64,15 +78,18 @@
 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.
+  test::ScopedRestoreICUDefaultLocale restore_locale;
   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"));
+  string16 clock24h_millis(ASCIIToUTF16("15:42:07.000"));
 
   // The default is 24h clock.
   EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(clock24h_millis, TimeFormatTimeOfDayWithMilliseconds(time));
   EXPECT_EQ(k24HourClock, GetHourClockType());
   // k{Keep,Drop}AmPm should not affect for 24h clock.
   EXPECT_EQ(clock24h,
@@ -97,6 +114,7 @@
 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.
+  test::ScopedRestoreICUDefaultLocale restore_locale;
   i18n::SetICUDefaultLocale("ja_JP");
 
   Time time(Time::FromLocalExploded(kTestDateTimeExploded));
@@ -130,6 +148,7 @@
 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".
+  test::ScopedRestoreICUDefaultLocale restore_locale;
   i18n::SetICUDefaultLocale("en_US");
 
   Time time(Time::FromLocalExploded(kTestDateTimeExploded));
@@ -139,7 +158,7 @@
 
   EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM"),
             TimeFormatShortDateAndTime(time));
-  EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM ") + GetShortTimeZone(),
+  EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM ") + GetShortTimeZone(time),
             TimeFormatShortDateAndTimeWithTimeZone(time));
 
   EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 at 3:42:07 PM"),
@@ -152,6 +171,7 @@
 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".
+  test::ScopedRestoreICUDefaultLocale restore_locale;
   i18n::SetICUDefaultLocale("en_GB");
 
   Time time(Time::FromLocalExploded(kTestDateTimeExploded));
@@ -160,7 +180,7 @@
   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(),
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07 ") + GetShortTimeZone(time),
             TimeFormatShortDateAndTimeWithTimeZone(time));
   EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 at 15:42:07"),
             TimeFormatFriendlyDateAndTime(time));
diff --git a/base/id_map.h b/base/id_map.h
index 852c138..b04bcdd 100644
--- a/base/id_map.h
+++ b/base/id_map.h
@@ -5,12 +5,12 @@
 #ifndef BASE_ID_MAP_H_
 #define BASE_ID_MAP_H_
 
+#include <stdint.h>
 #include <set>
 
-#include "base/basictypes.h"
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 
 // Ownership semantics - own pointer means the pointer is deleted in Remove()
 // & during destruction
@@ -30,26 +30,30 @@
 //
 // 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 {
+template <typename T,
+          IDMapOwnershipSemantics OS = IDMapExternalPointer,
+          typename K = int32_t>
+class IDMap {
  public:
-  typedef int32 KeyType;
+  using KeyType = K;
 
  private:
   typedef base::hash_map<KeyType, T*> HashTable;
 
  public:
   IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) {
-    // A number of consumers of IDMap create it on one thread but always access
-    // it from a different, but consitent, thread post-construction.
-    DetachFromThread();
+    // A number of consumers of IDMap create it on one thread but always
+    // access it from a different, but consistent, thread (or sequence)
+    // post-construction. The first call to CalledOnValidSequencedThread()
+    // will re-bind it.
+    sequence_checker_.DetachFromSequence();
   }
 
   ~IDMap() {
-    // Many IDMap's are static, and hence will be destroyed on the main thread.
-    // However, all the accesses may take place on another thread, such as the
-    // IO thread. Detaching again to clean this up.
-    DetachFromThread();
+    // Many IDMap's are static, and hence will be destroyed on the main
+    // thread. However, all the accesses may take place on another thread (or
+    // sequence), such as the IO thread. Detaching again to clean this up.
+    sequence_checker_.DetachFromSequence();
     Releaser<OS, 0>::release_all(&data_);
   }
 
@@ -59,7 +63,7 @@
 
   // Adds a view with an automatically generated unique ID. See AddWithID.
   KeyType Add(T* data) {
-    DCHECK(CalledOnValidThread());
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
     DCHECK(!check_on_null_data_ || data);
     KeyType this_id = next_id_;
     DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item";
@@ -73,14 +77,14 @@
   // 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(sequence_checker_.CalledOnValidSequencedThread());
     DCHECK(!check_on_null_data_ || data);
     DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
     data_[id] = data;
   }
 
   void Remove(KeyType id) {
-    DCHECK(CalledOnValidThread());
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
     typename HashTable::iterator i = data_.find(id);
     if (i == data_.end()) {
       NOTREACHED() << "Attempting to remove an item not in the list";
@@ -101,7 +105,7 @@
   // 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(sequence_checker_.CalledOnValidSequencedThread());
     DCHECK(!check_on_null_data_ || new_data);
     typename HashTable::iterator i = data_.find(id);
     if (i == data_.end()) {
@@ -115,7 +119,7 @@
   }
 
   void Clear() {
-    DCHECK(CalledOnValidThread());
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
     if (iteration_depth_ == 0) {
       Releaser<OS, 0>::release_all(&data_);
     } else {
@@ -126,12 +130,12 @@
   }
 
   bool IsEmpty() const {
-    DCHECK(CalledOnValidThread());
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
     return size() == 0u;
   }
 
   T* Lookup(KeyType id) const {
-    DCHECK(CalledOnValidThread());
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
     typename HashTable::const_iterator i = data_.find(id);
     if (i == data_.end())
       return NULL;
@@ -139,7 +143,7 @@
   }
 
   size_t size() const {
-    DCHECK(CalledOnValidThread());
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
     return data_.size() - removed_ids_.size();
   }
 
@@ -174,7 +178,7 @@
     }
 
     ~Iterator() {
-      DCHECK(map_->CalledOnValidThread());
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
 
       // We're going to decrement iteration depth. Make sure it's greater than
       // zero so that it doesn't become negative.
@@ -185,29 +189,29 @@
     }
 
     bool IsAtEnd() const {
-      DCHECK(map_->CalledOnValidThread());
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
       return iter_ == map_->data_.end();
     }
 
     KeyType GetCurrentKey() const {
-      DCHECK(map_->CalledOnValidThread());
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
       return iter_->first;
     }
 
     ReturnType* GetCurrentValue() const {
-      DCHECK(map_->CalledOnValidThread());
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
       return iter_->second;
     }
 
     void Advance() {
-      DCHECK(map_->CalledOnValidThread());
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
       ++iter_;
       SkipRemovedEntries();
     }
 
    private:
     void Init() {
-      DCHECK(map_->CalledOnValidThread());
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
       ++map_->iteration_depth_;
       SkipRemovedEntries();
     }
@@ -249,10 +253,8 @@
 
   void Compact() {
     DCHECK_EQ(0, iteration_depth_);
-    for (std::set<KeyType>::const_iterator i = removed_ids_.begin();
-         i != removed_ids_.end(); ++i) {
-      Remove(*i);
-    }
+    for (const auto& i : removed_ids_)
+      Remove(i);
     removed_ids_.clear();
   }
 
@@ -273,6 +275,8 @@
   // See description above setter.
   bool check_on_null_data_;
 
+  base::SequenceChecker sequence_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(IDMap);
 };
 
diff --git a/base/id_map_unittest.cc b/base/id_map_unittest.cc
index a9fb2b9..2cd6309 100644
--- a/base/id_map_unittest.cc
+++ b/base/id_map_unittest.cc
@@ -355,4 +355,16 @@
   EXPECT_EQ(owned_del_count, kCount);
 }
 
+TEST(IDMapTest, Int64KeyType) {
+  IDMap<TestObject, IDMapExternalPointer, int64_t> map;
+  TestObject obj1;
+  const int64_t kId1 = 999999999999999999;
+
+  map.AddWithID(&obj1, kId1);
+  EXPECT_EQ(&obj1, map.Lookup(kId1));
+
+  map.Remove(kId1);
+  EXPECT_TRUE(map.IsEmpty());
+}
+
 }  // namespace
diff --git a/base/ios/OWNERS b/base/ios/OWNERS
index 6256400..dc0be62 100644
--- a/base/ios/OWNERS
+++ b/base/ios/OWNERS
@@ -1,3 +1,4 @@
+droger@chromium.org
 qsr@chromium.org
 rohitrao@chromium.org
 stuartmorgan@chromium.org
diff --git a/base/ios/crb_protocol_observers.h b/base/ios/crb_protocol_observers.h
index 15d1656..8ff5878 100644
--- a/base/ios/crb_protocol_observers.h
+++ b/base/ios/crb_protocol_observers.h
@@ -13,6 +13,10 @@
 // protocol. The container forwards method invocations to its contained
 // observers, so that sending a message to all the observers is as simple as
 // sending the message to the container.
+// It is safe for an observer to remove itself or another observer while being
+// notified. It is also safe to add an other observer while being notified but
+// the newly added observer will not be notified as part of the current
+// notification dispatch.
 @interface CRBProtocolObservers : NSObject
 
 // The Objective-C protocol that the observers in this container conform to.
@@ -20,7 +24,7 @@
 
 // Returns a CRBProtocolObservers container for observers that conform to
 // |protocol|.
-+ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol;
++ (instancetype)observersWithProtocol:(Protocol*)protocol;
 
 // Adds |observer| to this container.
 - (void)addObserver:(id)observer;
@@ -28,6 +32,9 @@
 // Remove |observer| from this container.
 - (void)removeObserver:(id)observer;
 
+// Returns true if there are currently no observers.
+- (BOOL)empty;
+
 // Executes callback on every observer. |callback| cannot be nil.
 - (void)executeOnObservers:(ExecutionWithObserverBlock)callback;
 
diff --git a/base/ios/crb_protocol_observers.mm b/base/ios/crb_protocol_observers.mm
index ee9e23f..90a277b 100644
--- a/base/ios/crb_protocol_observers.mm
+++ b/base/ios/crb_protocol_observers.mm
@@ -5,10 +5,69 @@
 #import "base/ios/crb_protocol_observers.h"
 
 #include <objc/runtime.h>
+#include <algorithm>
+#include <vector>
 
 #include "base/logging.h"
 #include "base/mac/scoped_nsobject.h"
 
+@interface CRBProtocolObservers () {
+  base::scoped_nsobject<Protocol> _protocol;
+  // ivars declared here are private to the implementation but must be
+  // public for allowing the C++ |Iterator| class access to those ivars.
+ @public
+  // vector of weak pointers to observers.
+  std::vector<__unsafe_unretained id> _observers;
+  // The nested level of observer iteration.
+  // A depth of 0 means nobody is currently iterating on the list of observers.
+  int _invocationDepth;
+}
+
+// Removes nil observers from the list and is called when the
+// |_invocationDepth| reaches 0.
+- (void)compact;
+
+@end
+
+namespace {
+
+class Iterator {
+ public:
+  explicit Iterator(CRBProtocolObservers* protocol_observers);
+  ~Iterator();
+  id GetNext();
+
+ private:
+  CRBProtocolObservers* protocol_observers_;
+  size_t index_;
+  size_t max_index_;
+};
+
+Iterator::Iterator(CRBProtocolObservers* protocol_observers)
+    : protocol_observers_(protocol_observers),
+      index_(0),
+      max_index_(protocol_observers->_observers.size()) {
+  DCHECK(protocol_observers_);
+  ++protocol_observers->_invocationDepth;
+}
+
+Iterator::~Iterator() {
+  if (protocol_observers_ && --protocol_observers_->_invocationDepth == 0)
+    [protocol_observers_ compact];
+}
+
+id Iterator::GetNext() {
+  if (!protocol_observers_)
+    return nil;
+  auto& observers = protocol_observers_->_observers;
+  // Skip nil elements.
+  size_t max_index = std::min(max_index_, observers.size());
+  while (index_ < max_index && !observers[index_])
+    ++index_;
+  return index_ < max_index ? observers[index_++] : nil;
+}
+}
+
 @interface CRBProtocolObservers ()
 
 // Designated initializer.
@@ -16,12 +75,9 @@
 
 @end
 
-@implementation CRBProtocolObservers {
-  base::scoped_nsobject<Protocol> _protocol;
-  base::scoped_nsobject<NSHashTable> _observers;
-}
+@implementation CRBProtocolObservers
 
-+ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol {
++ (instancetype)observersWithProtocol:(Protocol*)protocol {
   return [[[self alloc] initWithProtocol:protocol] autorelease];
 }
 
@@ -34,7 +90,6 @@
   self = [super init];
   if (self) {
     _protocol.reset([protocol retain]);
-    _observers.reset([[NSHashTable weakObjectsHashTable] retain]);
   }
   return self;
 }
@@ -44,12 +99,34 @@
 }
 
 - (void)addObserver:(id)observer {
+  DCHECK(observer);
   DCHECK([observer conformsToProtocol:self.protocol]);
-  [_observers addObject:observer];
+
+  if (std::find(_observers.begin(), _observers.end(), observer) !=
+      _observers.end())
+    return;
+
+  _observers.push_back(observer);
 }
 
 - (void)removeObserver:(id)observer {
-  [_observers removeObject:observer];
+  DCHECK(observer);
+  auto it = std::find(_observers.begin(), _observers.end(), observer);
+  if (it != _observers.end()) {
+    if (_invocationDepth)
+      *it = nil;
+    else
+      _observers.erase(it);
+  }
+}
+
+- (BOOL)empty {
+  int count = 0;
+  for (id observer : _observers) {
+    if (observer != nil)
+      ++count;
+  }
+  return count == 0;
 }
 
 #pragma mark - NSObject
@@ -80,9 +157,13 @@
 }
 
 - (void)forwardInvocation:(NSInvocation*)invocation {
+  DCHECK(invocation);
+  if (_observers.empty())
+    return;
   SEL selector = [invocation selector];
-  base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
-  for (id observer in observers.get()) {
+  Iterator it(self);
+  id observer;
+  while ((observer = it.GetNext()) != nil) {
     if ([observer respondsToSelector:selector])
       [invocation invokeWithTarget:observer];
   }
@@ -90,10 +171,20 @@
 
 - (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
   DCHECK(callback);
-  base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
-  for (id observer in observers.get()) {
+  if (_observers.empty())
+    return;
+  Iterator it(self);
+  id observer;
+  while ((observer = it.GetNext()) != nil)
     callback(observer);
-  }
+}
+
+#pragma mark - Private
+
+- (void)compact {
+  DCHECK(!_invocationDepth);
+  _observers.erase(std::remove(_observers.begin(), _observers.end(), nil),
+                   _observers.end());
 }
 
 @end
diff --git a/base/ios/crb_protocol_observers_unittest.mm b/base/ios/crb_protocol_observers_unittest.mm
index d235c98..07f5cff 100644
--- a/base/ios/crb_protocol_observers_unittest.mm
+++ b/base/ios/crb_protocol_observers_unittest.mm
@@ -4,6 +4,7 @@
 
 #import "base/ios/crb_protocol_observers.h"
 #include "base/ios/weak_nsobject.h"
+#include "base/logging.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "base/mac/scoped_nsobject.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -18,6 +19,10 @@
 
 @optional
 - (void)optionalMethod;
+- (void)mutateByAddingObserver:(id<TestObserver>)observer;
+- (void)mutateByRemovingObserver:(id<TestObserver>)observer;
+- (void)nestedMutateByAddingObserver:(id<TestObserver>)observer;
+- (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer;
 
 @end
 
@@ -31,6 +36,12 @@
 @property(nonatomic, readonly) BOOL optionalMethodInvoked;
 @end
 
+@interface TestMutateObserver : TestCompleteObserver
+- (instancetype)initWithObserver:(CRBProtocolObservers*)observer
+    NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+@end
+
 namespace {
 
 class CRBProtocolObserversTest : public PlatformTest {
@@ -50,11 +61,16 @@
     complete_observer_.reset([[TestCompleteObserver alloc] init]);
     EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
     EXPECT_FALSE([complete_observer_ optionalMethodInvoked]);
+
+    mutate_observer_.reset(
+        [[TestMutateObserver alloc] initWithObserver:observers_.get()]);
+    EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
   }
 
   base::scoped_nsobject<id> observers_;
   base::scoped_nsobject<TestPartialObserver> partial_observer_;
   base::scoped_nsobject<TestCompleteObserver> complete_observer_;
+  base::scoped_nsobject<TestMutateObserver> mutate_observer_;
 };
 
 // Verifies basic functionality of -[CRBProtocolObservers addObserver:] and
@@ -119,6 +135,86 @@
   EXPECT_FALSE(weak_observer.get());
 }
 
+// Verifies that an observer can safely remove itself as observer while being
+// notified.
+TEST_F(CRBProtocolObserversTest, SelfMutateObservers) {
+  [observers_ addObserver:mutate_observer_];
+  EXPECT_FALSE([observers_ empty]);
+
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+
+  [mutate_observer_ reset];
+
+  [observers_ nestedMutateByRemovingObserver:mutate_observer_];
+  EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
+
+  [observers_ addObserver:partial_observer_];
+
+  [observers_ requiredMethod];
+  EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [observers_ removeObserver:partial_observer_];
+  EXPECT_TRUE([observers_ empty]);
+}
+
+// Verifies that - [CRBProtocolObservers addObserver:] and
+// - [CRBProtocolObservers removeObserver:] can be called while methods are
+// being forwarded.
+TEST_F(CRBProtocolObserversTest, MutateObservers) {
+  // Indirectly add an observer while forwarding an observer method.
+  [observers_ addObserver:mutate_observer_];
+
+  [observers_ mutateByAddingObserver:partial_observer_];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+  // Check that methods are correctly forwared to the indirectly added observer.
+  [mutate_observer_ reset];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [mutate_observer_ reset];
+  [partial_observer_ reset];
+
+  // Indirectly remove an observer while forwarding an observer method.
+  [observers_ mutateByRemovingObserver:partial_observer_];
+
+  // Check that method is not forwared to the indirectly removed observer.
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+}
+
+// Verifies that - [CRBProtocolObservers addObserver:] and
+// - [CRBProtocolObservers removeObserver:] can be called while methods are
+// being forwarded with a nested invocation depth > 0.
+TEST_F(CRBProtocolObserversTest, NestedMutateObservers) {
+  // Indirectly add an observer while forwarding an observer method.
+  [observers_ addObserver:mutate_observer_];
+
+  [observers_ nestedMutateByAddingObserver:partial_observer_];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+  // Check that methods are correctly forwared to the indirectly added observer.
+  [mutate_observer_ reset];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [mutate_observer_ reset];
+  [partial_observer_ reset];
+
+  // Indirectly remove an observer while forwarding an observer method.
+  [observers_ nestedMutateByRemovingObserver:partial_observer_];
+
+  // Check that method is not forwared to the indirectly removed observer.
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+}
+
 }  // namespace
 
 @implementation TestPartialObserver {
@@ -157,3 +253,38 @@
 }
 
 @end
+
+@implementation TestMutateObserver {
+  id _observers;  // weak
+}
+
+- (instancetype)initWithObserver:(CRBProtocolObservers*)observers {
+  self = [super init];
+  if (self) {
+    _observers = observers;
+  }
+  return self;
+}
+
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
+- (void)mutateByAddingObserver:(id<TestObserver>)observer {
+  [_observers addObserver:observer];
+}
+
+- (void)mutateByRemovingObserver:(id<TestObserver>)observer {
+  [_observers removeObserver:observer];
+}
+
+- (void)nestedMutateByAddingObserver:(id<TestObserver>)observer {
+  [_observers mutateByAddingObserver:observer];
+}
+
+- (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer {
+  [_observers mutateByRemovingObserver:observer];
+}
+
+@end
diff --git a/base/ios/device_util.mm b/base/ios/device_util.mm
index 1234562..4af8234 100644
--- a/base/ios/device_util.mm
+++ b/base/ios/device_util.mm
@@ -59,7 +59,7 @@
   std::string platform;
   size_t size = 0;
   sysctlbyname("hw.machine", NULL, &size, NULL, 0);
-  sysctlbyname("hw.machine", WriteInto(&platform, size), &size, NULL, 0);
+  sysctlbyname("hw.machine", base::WriteInto(&platform, size), &size, NULL, 0);
   return platform;
 }
 
diff --git a/base/ios/ios_util.h b/base/ios/ios_util.h
index d9d7e19..9f65339 100644
--- a/base/ios/ios_util.h
+++ b/base/ios/ios_util.h
@@ -14,9 +14,19 @@
 // Returns whether the operating system is iOS 8 or later.
 BASE_EXPORT bool IsRunningOnIOS8OrLater();
 
+// Returns whether the operating system is iOS 9 or later.
+BASE_EXPORT bool IsRunningOnIOS9OrLater();
+
 // Returns whether the operating system is at the given version or later.
 BASE_EXPORT bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix);
 
+// Returns whether iOS is signalling that an RTL text direction should be used
+// regardless of the current locale. This should not return true if the current
+// language is a "real" RTL language such as Arabic or Urdu; it should only
+// return true in cases where the RTL text direction has been forced (for
+// example by using the "RTL Psuedolanguage" option when launching from XCode).
+BASE_EXPORT bool IsInForcedRTL();
+
 }  // namespace ios
 }  // namespace base
 
diff --git a/base/ios/ios_util.mm b/base/ios/ios_util.mm
index ca0a24d..554a202 100644
--- a/base/ios/ios_util.mm
+++ b/base/ios/ios_util.mm
@@ -4,6 +4,8 @@
 
 #include "base/ios/ios_util.h"
 
+#import <Foundation/Foundation.h>
+
 #include "base/sys_info.h"
 
 namespace {
@@ -20,10 +22,15 @@
 namespace base {
 namespace ios {
 
+// When dropping iOS7 support, also address issues listed in crbug.com/502968.
 bool IsRunningOnIOS8OrLater() {
   return IsRunningOnOrLater(8, 0, 0);
 }
 
+bool IsRunningOnIOS9OrLater() {
+  return IsRunningOnOrLater(9, 0, 0);
+}
+
 bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix) {
   static const int32* current_version = OSVersionAsArray();
   int32 version[] = { major, minor, bug_fix };
@@ -34,5 +41,10 @@
   return true;
 }
 
+bool IsInForcedRTL() {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  return [defaults boolForKey:@"NSForceRightToLeftWritingDirection"];
+}
+
 }  // namespace ios
 }  // namespace base
diff --git a/base/ios/ns_error_util.h b/base/ios/ns_error_util.h
new file mode 100644
index 0000000..1012292
--- /dev/null
+++ b/base/ios/ns_error_util.h
@@ -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.
+
+#ifndef BASE_IOS_NS_ERROR_UTIL_H_
+#define BASE_IOS_NS_ERROR_UTIL_H_
+
+@class NSError;
+
+namespace base {
+namespace ios {
+
+// Iterates through |error|'s underlying errors and returns the first error for
+// which there is no underlying error.
+NSError* GetFinalUnderlyingErrorFromError(NSError* error);
+
+// Returns a copy of |original_error| with |underlying_error| appended to the
+// end of its underlying error chain.
+NSError* ErrorWithAppendedUnderlyingError(NSError* original_error,
+                                          NSError* underlying_error);
+
+}  // namespace ios
+}  // namespace base
+
+#endif  // BASE_IOS_NS_ERROR_UTIL_H_
diff --git a/base/ios/ns_error_util.mm b/base/ios/ns_error_util.mm
new file mode 100644
index 0000000..c44d9ee
--- /dev/null
+++ b/base/ios/ns_error_util.mm
@@ -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.
+
+#import "base/ios/ns_error_util.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+
+namespace base {
+namespace ios {
+
+namespace {
+// Iterates through |error|'s underlying errors and returns them in an array.
+NSArray* GetFullErrorChainForError(NSError* error) {
+  NSMutableArray* error_chain = [NSMutableArray array];
+  NSError* current_error = error;
+  while (current_error) {
+    DCHECK([current_error isKindOfClass:[NSError class]]);
+    [error_chain addObject:current_error];
+    current_error = current_error.userInfo[NSUnderlyingErrorKey];
+  }
+  return error_chain;
+}
+}  // namespace
+
+NSError* GetFinalUnderlyingErrorFromError(NSError* error) {
+  DCHECK(error);
+  return [GetFullErrorChainForError(error) lastObject];
+}
+
+NSError* ErrorWithAppendedUnderlyingError(NSError* original_error,
+                                          NSError* underlying_error) {
+  DCHECK(original_error);
+  DCHECK(underlying_error);
+  NSArray* error_chain = GetFullErrorChainForError(original_error);
+  NSError* current_error = underlying_error;
+  for (NSInteger idx = error_chain.count - 1; idx >= 0; --idx) {
+    NSError* error = error_chain[idx];
+    scoped_nsobject<NSMutableDictionary> user_info(
+        [error.userInfo mutableCopy]);
+    [user_info setObject:current_error forKey:NSUnderlyingErrorKey];
+    current_error = [NSError errorWithDomain:error.domain
+                                        code:error.code
+                                    userInfo:user_info];
+  }
+  return current_error;
+}
+
+}  // namespace ios
+}  // namespace base
diff --git a/base/json/json_file_value_serializer.cc b/base/json/json_file_value_serializer.cc
index 72a0970..9862703 100644
--- a/base/json/json_file_value_serializer.cc
+++ b/base/json/json_file_value_serializer.cc
@@ -100,8 +100,9 @@
   }
 }
 
-base::Value* JSONFileValueDeserializer::Deserialize(int* error_code,
-                                                    std::string* error_str) {
+scoped_ptr<base::Value> JSONFileValueDeserializer::Deserialize(
+    int* error_code,
+    std::string* error_str) {
   std::string json_string;
   int error = ReadFileToString(&json_string);
   if (error != JSON_NO_ERROR) {
diff --git a/base/json/json_file_value_serializer.h b/base/json/json_file_value_serializer.h
index aab47ee..4e5e09c 100644
--- a/base/json/json_file_value_serializer.h
+++ b/base/json/json_file_value_serializer.h
@@ -58,8 +58,8 @@
   // 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;
+  scoped_ptr<base::Value> Deserialize(int* error_code,
+                                      std::string* error_message) override;
 
   // This enum is designed to safely overlap with JSONReader::JsonParseError.
   enum JsonFileError {
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
index 4d79be3..9be690a 100644
--- a/base/json/json_parser.cc
+++ b/base/json/json_parser.cc
@@ -31,7 +31,7 @@
 // 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 {
+class DictionaryHiddenRootValue : public DictionaryValue {
  public:
   DictionaryHiddenRootValue(std::string* json, Value* root) : json_(json) {
     DCHECK(root->IsType(Value::TYPE_DICTIONARY));
@@ -43,7 +43,7 @@
 
     // 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());
+    scoped_ptr<DictionaryValue> copy(DeepCopy());
     copy->Swap(other);
 
     // Then erase the contents of the current dictionary and swap in the
@@ -81,7 +81,7 @@
   DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue);
 };
 
-class ListHiddenRootValue : public base::ListValue {
+class ListHiddenRootValue : public ListValue {
  public:
   ListHiddenRootValue(std::string* json, Value* root) : json_(json) {
     DCHECK(root->IsType(Value::TYPE_LIST));
@@ -93,7 +93,7 @@
 
     // 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());
+    scoped_ptr<ListValue> copy(DeepCopy());
     copy->Swap(other);
 
     // Then erase the contents of the current list and swap in the new contents,
@@ -130,14 +130,14 @@
 // 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 {
+class JSONStringValue : public Value {
  public:
-  explicit JSONStringValue(const base::StringPiece& piece)
+  explicit JSONStringValue(const StringPiece& piece)
       : Value(TYPE_STRING),
         string_piece_(piece) {
   }
 
-  // Overridden from base::Value:
+  // Overridden from Value:
   bool GetAsString(std::string* out_value) const override {
     string_piece_.CopyToString(out_value);
     return true;
@@ -157,7 +157,7 @@
 
  private:
   // The location in the original input stream.
-  base::StringPiece string_piece_;
+  StringPiece string_piece_;
 
   DISALLOW_COPY_AND_ASSIGN(JSONStringValue);
 };
@@ -776,11 +776,17 @@
 
     uint32 code_point = CBU16_GET_SUPPLEMENTARY(code_unit16_high,
                                                 code_unit16_low);
+    if (!IsValidCharacter(code_point))
+      return false;
+
     offset = 0;
     CBU8_APPEND_UNSAFE(code_unit8, offset, code_point);
   } else {
     // Not a surrogate.
     DCHECK(CBU16_IS_SINGLE(code_unit16_high));
+    if (!IsValidCharacter(code_unit16_high))
+      return false;
+
     CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high);
   }
 
@@ -789,6 +795,8 @@
 }
 
 void JSONParser::DecodeUTF8(const int32& point, StringBuilder* dest) {
+  DCHECK(IsValidCharacter(point));
+
   // Anything outside of the basic ASCII plane will need to be decoded from
   // int32 to a multi-byte sequence.
   if (point < kExtendedASCIIStart) {
@@ -872,7 +880,7 @@
     return new FundamentalValue(num_int);
 
   double num_double;
-  if (base::StringToDouble(num_string.as_string(), &num_double) &&
+  if (StringToDouble(num_string.as_string(), &num_double) &&
       std::isfinite(num_double)) {
     return new FundamentalValue(num_double);
   }
diff --git a/base/json/json_parser.h b/base/json/json_parser.h
index b4d0b1b..ac1ad85 100644
--- a/base/json/json_parser.h
+++ b/base/json/json_parser.h
@@ -10,31 +10,14 @@
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/gtest_prod_util.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;
@@ -57,7 +40,7 @@
 // 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 {
+class BASE_EXPORT JSONParser {
  public:
   explicit JSONParser(int options);
   ~JSONParser();
diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc
index 74e2026..c5a1710 100644
--- a/base/json/json_parser_unittest.cc
+++ b/base/json/json_parser_unittest.cc
@@ -203,17 +203,16 @@
   // 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));
+  scoped_ptr<Value> root = JSONReader::ReadAndReturnError(
+      "[42]", JSON_PARSE_RFC, &error_code, &error_message);
   EXPECT_TRUE(error_message.empty());
   EXPECT_EQ(0, error_code);
 
   // Test line and column counting
   const char big_json[] = "[\n0,\n1,\n2,\n3,4,5,6 7,\n8,\n9\n]";
   // error here ----------------------------------^
-  root.reset(JSONReader::ReadAndReturnError(big_json, JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError(big_json, JSON_PARSE_RFC, &error_code,
+                                        &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
             error_message);
@@ -225,16 +224,16 @@
   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));
+  root = JSONReader::ReadAndReturnError(big_json_crlf, JSON_PARSE_RFC,
+                                        &error_code, &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
             error_message);
   EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
 
   // Test each of the error conditions
-  root.reset(JSONReader::ReadAndReturnError("{},{}", JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError("{},{}", JSON_PARSE_RFC, &error_code,
+                                        &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3,
       JSONReader::kUnexpectedDataAfterRoot), error_message);
@@ -245,57 +244,56 @@
     nested_json.insert(nested_json.begin(), '[');
     nested_json.append(1, ']');
   }
-  root.reset(JSONReader::ReadAndReturnError(nested_json, JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError(nested_json, JSON_PARSE_RFC,
+                                        &error_code, &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 100, JSONReader::kTooMuchNesting),
             error_message);
   EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code);
 
-  root.reset(JSONReader::ReadAndReturnError("[1,]", JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError("[1,]", JSON_PARSE_RFC, &error_code,
+                                        &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma),
             error_message);
   EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
 
-  root.reset(JSONReader::ReadAndReturnError("{foo:\"bar\"}", JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError("{foo:\"bar\"}", JSON_PARSE_RFC,
+                                        &error_code, &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2,
       JSONReader::kUnquotedDictionaryKey), error_message);
   EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code);
 
-  root.reset(JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}",
-                                            JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}", JSON_PARSE_RFC,
+                                        &error_code, &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma),
             error_message);
 
-  root.reset(JSONReader::ReadAndReturnError("[nu]", JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError("[nu]", JSON_PARSE_RFC, &error_code,
+                                        &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError),
             error_message);
   EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
 
-  root.reset(JSONReader::ReadAndReturnError("[\"xxx\\xq\"]", JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError("[\"xxx\\xq\"]", JSON_PARSE_RFC,
+                                        &error_code, &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
             error_message);
   EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
 
-  root.reset(JSONReader::ReadAndReturnError("[\"xxx\\uq\"]", JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError("[\"xxx\\uq\"]", JSON_PARSE_RFC,
+                                        &error_code, &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
             error_message);
   EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
 
-  root.reset(JSONReader::ReadAndReturnError("[\"xxx\\q\"]", JSON_PARSE_RFC,
-                                            &error_code, &error_message));
+  root = JSONReader::ReadAndReturnError("[\"xxx\\q\"]", JSON_PARSE_RFC,
+                                        &error_code, &error_message);
   EXPECT_FALSE(root.get());
   EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
             error_message);
@@ -309,11 +307,18 @@
       "[\"😇\",[],[],[],{\"google:suggesttype\":[]}]";
   std::string error_message;
   int error_code = 0;
-  scoped_ptr<Value> root(
-      JSONReader::ReadAndReturnError(kUtf8Data, JSON_PARSE_RFC, &error_code,
-                                     &error_message));
+  scoped_ptr<Value> root = JSONReader::ReadAndReturnError(
+      kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message);
   EXPECT_TRUE(root.get()) << error_message;
 }
 
+TEST_F(JSONParserTest, DecodeUnicodeNonCharacter) {
+  // Tests Unicode code points (encoded as escaped UTF-16) that are not valid
+  // characters.
+  EXPECT_FALSE(JSONReader::Read("[\"\\ufdd0\"]"));
+  EXPECT_FALSE(JSONReader::Read("[\"\\ufffe\"]"));
+  EXPECT_FALSE(JSONReader::Read("[\"\\ud83f\\udffe\"]"));
+}
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index e17d450..015df43 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -6,12 +6,13 @@
 
 #include "base/json/json_parser.h"
 #include "base/logging.h"
+#include "base/values.h"
 
 namespace base {
 
 // Values 1000 and above are used by JSONFileValueSerializer::JsonFileError.
-COMPILE_ASSERT(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
-               json_reader_error_out_of_bounds);
+static_assert(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
+              "JSONReader error out of bounds");
 
 const char JSONReader::kInvalidEscape[] =
     "Invalid escape sequence.";
@@ -42,34 +43,33 @@
 }
 
 // static
-Value* JSONReader::Read(const StringPiece& json) {
+scoped_ptr<Value> JSONReader::Read(const StringPiece& json) {
   internal::JSONParser parser(JSON_PARSE_RFC);
-  return parser.Parse(json);
+  return make_scoped_ptr(parser.Parse(json));
 }
 
 // static
-Value* JSONReader::Read(const StringPiece& json,
-                        int options) {
+scoped_ptr<Value> JSONReader::Read(const StringPiece& json, int options) {
   internal::JSONParser parser(options);
-  return parser.Parse(json);
+  return make_scoped_ptr(parser.Parse(json));
 }
 
+
 // static
-Value* JSONReader::ReadAndReturnError(const StringPiece& json,
-                                      int options,
-                                      int* error_code_out,
-                                      std::string* error_msg_out) {
+scoped_ptr<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;
+  scoped_ptr<Value> root(parser.Parse(json));
+  if (!root) {
+    if (error_code_out)
+      *error_code_out = parser.error_code();
+    if (error_msg_out)
+      *error_msg_out = parser.GetErrorMessage();
+  }
 
-  if (error_code_out)
-    *error_code_out = parser.error_code();
-  if (error_msg_out)
-    *error_msg_out = parser.GetErrorMessage();
-
-  return NULL;
+  return root;
 }
 
 // static
@@ -99,8 +99,8 @@
   }
 }
 
-Value* JSONReader::ReadToValue(const std::string& json) {
-  return parser_->Parse(json);
+scoped_ptr<Value> JSONReader::ReadToValue(const std::string& json) {
+  return make_scoped_ptr(parser_->Parse(json));
 }
 
 JSONReader::JsonParseError JSONReader::error_code() const {
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
index fd053d4..46d1682 100644
--- a/base/json/json_reader.h
+++ b/base/json/json_reader.h
@@ -94,28 +94,28 @@
 
   // 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);
+  static scoped_ptr<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);
+  static scoped_ptr<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);
+  static scoped_ptr<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);
+  scoped_ptr<Value> ReadToValue(const std::string& json);
 
   // Returns the error code if the last call to ReadToValue() failed.
   // Returns JSON_NO_ERROR otherwise.
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
index a3ec4f7..1dc20d7 100644
--- a/base/json/json_reader_unittest.cc
+++ b/base/json/json_reader_unittest.cc
@@ -19,37 +19,36 @@
 
 TEST(JSONReaderTest, Reading) {
   // some whitespace checking
-  scoped_ptr<Value> root;
-  root.reset(JSONReader().ReadToValue("   null   "));
+  scoped_ptr<Value> root = JSONReader().ReadToValue("   null   ");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
 
   // Invalid JSON string
-  root.reset(JSONReader().ReadToValue("nu"));
+  root = JSONReader().ReadToValue("nu");
   EXPECT_FALSE(root.get());
 
   // Simple bool
-  root.reset(JSONReader().ReadToValue("true  "));
+  root = JSONReader().ReadToValue("true  ");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
 
   // Embedded comment
-  root.reset(JSONReader().ReadToValue("/* comment */null"));
+  root = JSONReader().ReadToValue("/* comment */null");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
-  root.reset(JSONReader().ReadToValue("40 /* comment */"));
+  root = JSONReader().ReadToValue("40 /* comment */");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
-  root.reset(JSONReader().ReadToValue("true // comment"));
+  root = JSONReader().ReadToValue("true // comment");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
-  root.reset(JSONReader().ReadToValue("/* comment */\"sample string\""));
+  root = JSONReader().ReadToValue("/* comment */\"sample string\"");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
   std::string value;
   EXPECT_TRUE(root->GetAsString(&value));
   EXPECT_EQ("sample string", value);
-  root.reset(JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]"));
+  root = JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]");
   ASSERT_TRUE(root.get());
   ListValue* list = static_cast<ListValue*>(root.get());
   EXPECT_EQ(2u, list->GetSize());
@@ -58,42 +57,42 @@
   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]"));
+  root = 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"));
+  root = JSONReader().ReadToValue("/* comment **/42");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
   EXPECT_TRUE(root->GetAsInteger(&int_val));
   EXPECT_EQ(42, int_val);
-  root.reset(JSONReader().ReadToValue(
+  root = JSONReader().ReadToValue(
       "/* comment **/\n"
       "// */ 43\n"
-      "44"));
+      "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"));
+  root = JSONReader().ReadToValue("43");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
   EXPECT_TRUE(root->GetAsInteger(&int_val));
   EXPECT_EQ(43, int_val);
 
   // According to RFC4627, oct, hex, and leading zeros are invalid JSON.
-  root.reset(JSONReader().ReadToValue("043"));
+  root = JSONReader().ReadToValue("043");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("0x43"));
+  root = JSONReader().ReadToValue("0x43");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("00"));
+  root = 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"));
+  root = JSONReader().ReadToValue("0");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
   int_val = 1;
@@ -102,14 +101,14 @@
 
   // Numbers that overflow ints should succeed, being internally promoted to
   // storage as doubles
-  root.reset(JSONReader().ReadToValue("2147483648"));
+  root = JSONReader().ReadToValue("2147483648");
   ASSERT_TRUE(root.get());
   double double_val;
   EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
   double_val = 0.0;
   EXPECT_TRUE(root->GetAsDouble(&double_val));
   EXPECT_DOUBLE_EQ(2147483648.0, double_val);
-  root.reset(JSONReader().ReadToValue("-2147483649"));
+  root = JSONReader().ReadToValue("-2147483649");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
   double_val = 0.0;
@@ -117,42 +116,42 @@
   EXPECT_DOUBLE_EQ(-2147483649.0, double_val);
 
   // Parse a double
-  root.reset(JSONReader().ReadToValue("43.1"));
+  root = JSONReader().ReadToValue("43.1");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
   double_val = 0.0;
   EXPECT_TRUE(root->GetAsDouble(&double_val));
   EXPECT_DOUBLE_EQ(43.1, double_val);
 
-  root.reset(JSONReader().ReadToValue("4.3e-1"));
+  root = JSONReader().ReadToValue("4.3e-1");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
   double_val = 0.0;
   EXPECT_TRUE(root->GetAsDouble(&double_val));
   EXPECT_DOUBLE_EQ(.43, double_val);
 
-  root.reset(JSONReader().ReadToValue("2.1e0"));
+  root = JSONReader().ReadToValue("2.1e0");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
   double_val = 0.0;
   EXPECT_TRUE(root->GetAsDouble(&double_val));
   EXPECT_DOUBLE_EQ(2.1, double_val);
 
-  root.reset(JSONReader().ReadToValue("2.1e+0001"));
+  root = JSONReader().ReadToValue("2.1e+0001");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
   double_val = 0.0;
   EXPECT_TRUE(root->GetAsDouble(&double_val));
   EXPECT_DOUBLE_EQ(21.0, double_val);
 
-  root.reset(JSONReader().ReadToValue("0.01"));
+  root = JSONReader().ReadToValue("0.01");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
   double_val = 0.0;
   EXPECT_TRUE(root->GetAsDouble(&double_val));
   EXPECT_DOUBLE_EQ(0.01, double_val);
 
-  root.reset(JSONReader().ReadToValue("1.00"));
+  root = JSONReader().ReadToValue("1.00");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
   double_val = 0.0;
@@ -160,43 +159,43 @@
   EXPECT_DOUBLE_EQ(1.0, double_val);
 
   // Fractional parts must have a digit before and after the decimal point.
-  root.reset(JSONReader().ReadToValue("1."));
+  root = JSONReader().ReadToValue("1.");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue(".1"));
+  root = JSONReader().ReadToValue(".1");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("1.e10"));
+  root = JSONReader().ReadToValue("1.e10");
   EXPECT_FALSE(root.get());
 
   // Exponent must have a digit following the 'e'.
-  root.reset(JSONReader().ReadToValue("1e"));
+  root = JSONReader().ReadToValue("1e");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("1E"));
+  root = JSONReader().ReadToValue("1E");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("1e1."));
+  root = JSONReader().ReadToValue("1e1.");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("1e1.0"));
+  root = JSONReader().ReadToValue("1e1.0");
   EXPECT_FALSE(root.get());
 
   // INF/-INF/NaN are not valid
-  root.reset(JSONReader().ReadToValue("1e1000"));
+  root = JSONReader().ReadToValue("1e1000");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("-1e1000"));
+  root = JSONReader().ReadToValue("-1e1000");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("NaN"));
+  root = JSONReader().ReadToValue("NaN");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("nan"));
+  root = JSONReader().ReadToValue("nan");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("inf"));
+  root = JSONReader().ReadToValue("inf");
   EXPECT_FALSE(root.get());
 
   // Invalid number formats
-  root.reset(JSONReader().ReadToValue("4.3.1"));
+  root = JSONReader().ReadToValue("4.3.1");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("4e3.1"));
+  root = JSONReader().ReadToValue("4e3.1");
   EXPECT_FALSE(root.get());
 
   // Test string parser
-  root.reset(JSONReader().ReadToValue("\"hello world\""));
+  root = JSONReader().ReadToValue("\"hello world\"");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
   std::string str_val;
@@ -204,7 +203,7 @@
   EXPECT_EQ("hello world", str_val);
 
   // Empty string
-  root.reset(JSONReader().ReadToValue("\"\""));
+  root = JSONReader().ReadToValue("\"\"");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
   str_val.clear();
@@ -212,7 +211,7 @@
   EXPECT_EQ("", str_val);
 
   // Test basic string escapes
-  root.reset(JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\""));
+  root = JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\"");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
   str_val.clear();
@@ -220,7 +219,7 @@
   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\""));
+  root = JSONReader().ReadToValue("\"\\x41\\x00\\u1234\"");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
   str_val.clear();
@@ -228,71 +227,70 @@
   EXPECT_EQ(std::wstring(L"A\0\x1234", 3), UTF8ToWide(str_val));
 
   // Test invalid strings
-  root.reset(JSONReader().ReadToValue("\"no closing quote"));
+  root = JSONReader().ReadToValue("\"no closing quote");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("\"\\z invalid escape char\""));
+  root = JSONReader().ReadToValue("\"\\z invalid escape char\"");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("\"\\xAQ invalid hex code\""));
+  root = JSONReader().ReadToValue("\"\\xAQ invalid hex code\"");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("not enough hex chars\\x1\""));
+  root = JSONReader().ReadToValue("not enough hex chars\\x1\"");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("\"not enough escape chars\\u123\""));
+  root = JSONReader().ReadToValue("\"not enough escape chars\\u123\"");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("\"extra backslash at end of input\\\""));
+  root = JSONReader().ReadToValue("\"extra backslash at end of input\\\"");
   EXPECT_FALSE(root.get());
 
   // Basic array
-  root.reset(JSONReader::Read("[true, false, null]"));
+  root = 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));
+  scoped_ptr<Value> root2 =
+      JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_TRUE(root->Equals(root2.get()));
 
   // Empty array
-  root.reset(JSONReader::Read("[]"));
+  root = 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]"));
+  root = 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));
+  root2 = 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"));
+  root = JSONReader::Read("[[true], [], [false, [], [null]], null");
   EXPECT_FALSE(root.get());
 
   // Invalid, too many commas
-  root.reset(JSONReader::Read("[true,, null]"));
+  root = JSONReader::Read("[true,, null]");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS));
+  root = JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_FALSE(root.get());
 
   // Invalid, no commas
-  root.reset(JSONReader::Read("[true null]"));
+  root = JSONReader::Read("[true null]");
   EXPECT_FALSE(root.get());
 
   // Invalid, trailing comma
-  root.reset(JSONReader::Read("[true,]"));
+  root = 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));
+  root = JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
   list = static_cast<ListValue*>(root.get());
@@ -306,22 +304,22 @@
 
   // Don't allow empty elements, even if |allow_trailing_comma| is
   // true.
-  root.reset(JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS));
+  root = JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS));
+  root = JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS));
+  root = JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS));
+  root = JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_FALSE(root.get());
 
   // Test objects
-  root.reset(JSONReader::Read("{}"));
+  root = JSONReader::Read("{}");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
 
-  root.reset(JSONReader::Read(
-      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }"));
+  root = 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());
@@ -335,34 +333,36 @@
   EXPECT_TRUE(dict_val->GetString("S", &str_val));
   EXPECT_EQ("str", str_val);
 
-  root2.reset(JSONReader::Read(
+  root2 = JSONReader::Read(
       "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }",
-      JSON_ALLOW_TRAILING_COMMAS));
+      JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(root2.get());
   EXPECT_TRUE(root->Equals(root2.get()));
 
   // Test newline equivalence.
-  root2.reset(JSONReader::Read(
+  root2 = JSONReader::Read(
       "{\n"
       "  \"number\":9.87654321,\n"
       "  \"null\":null,\n"
       "  \"\\x53\":\"str\",\n"
-      "}\n", JSON_ALLOW_TRAILING_COMMAS));
+      "}\n",
+      JSON_ALLOW_TRAILING_COMMAS);
   ASSERT_TRUE(root2.get());
   EXPECT_TRUE(root->Equals(root2.get()));
 
-  root2.reset(JSONReader::Read(
+  root2 = JSONReader::Read(
       "{\r\n"
       "  \"number\":9.87654321,\r\n"
       "  \"null\":null,\r\n"
       "  \"\\x53\":\"str\",\r\n"
-      "}\r\n", JSON_ALLOW_TRAILING_COMMAS));
+      "}\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\":{}}"));
+  root = 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());
@@ -377,14 +377,13 @@
   inner_dict = NULL;
   EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict));
 
-  root2.reset(JSONReader::Read(
+  root2 = JSONReader::Read(
       "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}",
-      JSON_ALLOW_TRAILING_COMMAS));
+      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}}"));
+  root = 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());
@@ -401,7 +400,7 @@
                                                          &integer_value));
   EXPECT_EQ(1, integer_value);
 
-  root.reset(JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}"));
+  root = 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());
@@ -411,45 +410,45 @@
   EXPECT_EQ(1, integer_value);
 
   // Invalid, no closing brace
-  root.reset(JSONReader::Read("{\"a\": true"));
+  root = JSONReader::Read("{\"a\": true");
   EXPECT_FALSE(root.get());
 
   // Invalid, keys must be quoted
-  root.reset(JSONReader::Read("{foo:true}"));
+  root = JSONReader::Read("{foo:true}");
   EXPECT_FALSE(root.get());
 
   // Invalid, trailing comma
-  root.reset(JSONReader::Read("{\"a\":true,}"));
+  root = JSONReader::Read("{\"a\":true,}");
   EXPECT_FALSE(root.get());
 
   // Invalid, too many commas
-  root.reset(JSONReader::Read("{\"a\":true,,\"b\":false}"));
+  root = JSONReader::Read("{\"a\":true,,\"b\":false}");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader::Read("{\"a\":true,,\"b\":false}",
-                              JSON_ALLOW_TRAILING_COMMAS));
+  root =
+      JSONReader::Read("{\"a\":true,,\"b\":false}", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_FALSE(root.get());
 
   // Invalid, no separator
-  root.reset(JSONReader::Read("{\"a\" \"b\"}"));
+  root = JSONReader::Read("{\"a\" \"b\"}");
   EXPECT_FALSE(root.get());
 
   // Invalid, lone comma.
-  root.reset(JSONReader::Read("{,}"));
+  root = JSONReader::Read("{,}");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS));
+  root = JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS));
+  root = JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS));
+  root = JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS);
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader::Read("{\"a\":true,,\"b\":false}",
-                              JSON_ALLOW_TRAILING_COMMAS));
+  root =
+      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));
+  root = JSONReader::Read(evil);
   EXPECT_FALSE(root.get());
 
   // A few thousand adjacent lists is fine.
@@ -459,22 +458,22 @@
     not_evil.append("[],");
   }
   not_evil.append("[]]");
-  root.reset(JSONReader::Read(not_evil));
+  root = 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\""));
+  root = JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\"");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
   str_val.clear();
   EXPECT_TRUE(root->GetAsString(&str_val));
   EXPECT_EQ(L"\x7f51\x9875", UTF8ToWide(str_val));
 
-  root.reset(JSONReader().ReadToValue(
-      "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}"));
+  root = JSONReader().ReadToValue(
+      "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
   EXPECT_TRUE(root->GetAsDictionary(&dict_val));
@@ -482,22 +481,22 @@
   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\""));
+  root = JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\"");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("\"123\xc0\x81\""));
+  root = JSONReader().ReadToValue("\"123\xc0\x81\"");
   EXPECT_FALSE(root.get());
-  root.reset(JSONReader().ReadToValue("\"abc\xc0\xae\""));
+  root = JSONReader().ReadToValue("\"abc\xc0\xae\"");
   EXPECT_FALSE(root.get());
 
   // Test utf16 encoded strings.
-  root.reset(JSONReader().ReadToValue("\"\\u20ac3,14\""));
+  root = JSONReader().ReadToValue("\"\\u20ac3,14\"");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
   str_val.clear();
   EXPECT_TRUE(root->GetAsString(&str_val));
   EXPECT_EQ("\xe2\x82\xac""3,14", str_val);
 
-  root.reset(JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\""));
+  root = JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\"");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
   str_val.clear();
@@ -516,25 +515,25 @@
     "\"\\ud83\\foo\""  // No lower surrogate.
   };
   for (size_t i = 0; i < arraysize(cases); ++i) {
-    root.reset(JSONReader().ReadToValue(cases[i]));
+    root = JSONReader().ReadToValue(cases[i]);
     EXPECT_FALSE(root.get()) << cases[i];
   }
 
   // Test literal root objects.
-  root.reset(JSONReader::Read("null"));
+  root = JSONReader::Read("null");
   EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
 
-  root.reset(JSONReader::Read("true"));
+  root = JSONReader::Read("true");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->GetAsBoolean(&bool_value));
   EXPECT_TRUE(bool_value);
 
-  root.reset(JSONReader::Read("10"));
+  root = JSONReader::Read("10");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->GetAsInteger(&integer_value));
   EXPECT_EQ(10, integer_value);
 
-  root.reset(JSONReader::Read("\"root\""));
+  root = JSONReader::Read("\"root\"");
   ASSERT_TRUE(root.get());
   EXPECT_TRUE(root->GetAsString(&str_val));
   EXPECT_EQ("root", str_val);
@@ -567,7 +566,7 @@
   scoped_ptr<Value> list_value_1;
 
   {
-    scoped_ptr<Value> root(JSONReader::Read(
+    scoped_ptr<Value> root = JSONReader::Read(
         "{"
         "  \"test\": {"
         "    \"foo\": true,"
@@ -579,7 +578,8 @@
         "    \"a\","
         "    \"b\""
         "  ]"
-        "}", JSON_DETACHABLE_CHILDREN));
+        "}",
+        JSON_DETACHABLE_CHILDREN);
     ASSERT_TRUE(root.get());
 
     DictionaryValue* root_dict = NULL;
diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc
index debf9f0..af7e010 100644
--- a/base/json/json_string_value_serializer.cc
+++ b/base/json/json_string_value_serializer.cc
@@ -37,7 +37,7 @@
   if (pretty_print_)
     options |= base::JSONWriter::OPTIONS_PRETTY_PRINT;
 
-  return base::JSONWriter::WriteWithOptions(&root, options, json_string_);
+  return base::JSONWriter::WriteWithOptions(root, options, json_string_);
 }
 
 JSONStringValueDeserializer::JSONStringValueDeserializer(
@@ -48,10 +48,11 @@
 
 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,
+scoped_ptr<Value> JSONStringValueDeserializer::Deserialize(
+    int* error_code,
+    std::string* error_str) {
+  return base::JSONReader::ReadAndReturnError(
+      json_string_, allow_trailing_comma_ ? base::JSON_ALLOW_TRAILING_COMMAS
+                                          : base::JSON_PARSE_RFC,
       error_code, error_str);
 }
diff --git a/base/json/json_string_value_serializer.h b/base/json/json_string_value_serializer.h
index bc0e66d..90f697d 100644
--- a/base/json/json_string_value_serializer.h
+++ b/base/json/json_string_value_serializer.h
@@ -59,8 +59,8 @@
   // 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;
+  scoped_ptr<base::Value> Deserialize(int* error_code,
+                                      std::string* error_message) override;
 
   void set_allow_trailing_comma(bool new_value) {
     allow_trailing_comma_ = new_value;
diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc
index 7d48f39..9038610 100644
--- a/base/json/json_value_converter_unittest.cc
+++ b/base/json/json_value_converter_unittest.cc
@@ -106,7 +106,7 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
   EXPECT_TRUE(converter.Convert(*value.get(), &message));
@@ -148,7 +148,7 @@
       "  }]\n"
       "}\n";
 
-  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
   NestedMessage message;
   base::JSONValueConverter<NestedMessage> converter;
   EXPECT_TRUE(converter.Convert(*value.get(), &message));
@@ -190,7 +190,7 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
   EXPECT_FALSE(converter.Convert(*value.get(), &message));
@@ -206,7 +206,7 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  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.
@@ -229,7 +229,7 @@
       "  \"ints\": [1, 2]"
       "}\n";
 
-  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
   EXPECT_FALSE(converter.Convert(*value.get(), &message));
@@ -246,7 +246,7 @@
       "  \"ints\": [1, false]"
       "}\n";
 
-  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
   SimpleMessage message;
   base::JSONValueConverter<SimpleMessage> converter;
   EXPECT_FALSE(converter.Convert(*value.get(), &message));
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc
index b8aebe0..7da11cf 100644
--- a/base/json/json_value_serializer_unittest.cc
+++ b/base/json/json_value_serializer_unittest.cc
@@ -75,7 +75,7 @@
 }
 
 void ValidateJsonList(const std::string& json) {
-  scoped_ptr<Value> root(JSONReader::Read(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());
@@ -93,8 +93,8 @@
 
   int error_code = 0;
   std::string error_message;
-  scoped_ptr<Value> value(
-      str_deserializer.Deserialize(&error_code, &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());
@@ -112,8 +112,8 @@
 
   int error_code = 0;
   std::string error_message;
-  scoped_ptr<Value> value(
-      str_deserializer.Deserialize(&error_code, &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());
@@ -129,14 +129,14 @@
 
   int error_code = 0;
   std::string error_message;
-  scoped_ptr<Value> value(
-      str_deserializer.Deserialize(&error_code, &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));
+  value = str_deserializer.Deserialize(&error_code, &error_message);
   ASSERT_TRUE(value.get());
   ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
   // Verify if the same JSON is still there.
@@ -157,8 +157,8 @@
 
   int error_code = 0;
   std::string error_message;
-  scoped_ptr<Value> value(
-      file_deserializer.Deserialize(&error_code, &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());
@@ -182,14 +182,14 @@
   // 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));
+  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));
+  value = file_deserializer.Deserialize(&error_code, &error_message);
   ASSERT_TRUE(value.get());
   ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
   // Verify if the same JSON is still there.
@@ -205,9 +205,9 @@
   JSONStringValueDeserializer deserializer(kTestWithCommas);
   deserializer.set_allow_trailing_comma(true);
   JSONStringValueDeserializer deserializer_expected(kTestNoCommas);
-  root.reset(deserializer.Deserialize(NULL, NULL));
+  root = deserializer.Deserialize(NULL, NULL);
   ASSERT_TRUE(root.get());
-  root_expected.reset(deserializer_expected.Deserialize(NULL, NULL));
+  root_expected = deserializer_expected.Deserialize(NULL, NULL);
   ASSERT_TRUE(root_expected.get());
   ASSERT_TRUE(root->Equals(root_expected.get()));
 }
@@ -216,7 +216,7 @@
   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));
+  scoped_ptr<Value> root = deserializer.Deserialize(NULL, NULL);
   ASSERT_TRUE(root.get());
   ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
 
@@ -302,7 +302,7 @@
   std::string output_js;
   DictionaryValue valueRoot;
   valueRoot.SetString("all_chars", all_chars);
-  JSONWriter::Write(&valueRoot, &output_js);
+  JSONWriter::Write(valueRoot, &output_js);
   ASSERT_EQ(expected_output, output_js);
 
   // Test JSONValueSerializer interface (uses JSONWriter).
@@ -326,7 +326,7 @@
 
   // escaped ascii text -> json
   JSONStringValueDeserializer deserializer(kExpected);
-  scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
+  scoped_ptr<Value> deserial_root = deserializer.Deserialize(NULL, NULL);
   ASSERT_TRUE(deserial_root.get());
   DictionaryValue* dict_root =
       static_cast<DictionaryValue*>(deserial_root.get());
@@ -350,7 +350,7 @@
 
   // escaped ascii text -> json
   JSONStringValueDeserializer deserializer(kExpected);
-  scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
+  scoped_ptr<Value> deserial_root = deserializer.Deserialize(NULL, NULL);
   ASSERT_TRUE(deserial_root.get());
   DictionaryValue* dict_root =
       static_cast<DictionaryValue*>(deserial_root.get());
@@ -361,7 +361,7 @@
   // Test converting escaped regular chars
   static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}";
   JSONStringValueDeserializer deserializer2(kEscapedChars);
-  deserial_root.reset(deserializer2.Deserialize(NULL, NULL));
+  deserial_root = deserializer2.Deserialize(NULL, NULL);
   ASSERT_TRUE(deserial_root.get());
   dict_root = static_cast<DictionaryValue*>(deserial_root.get());
   ASSERT_TRUE(dict_root->GetString("test", &test_value));
@@ -376,10 +376,8 @@
   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 */ \"]"));
+  scoped_ptr<Value> root = JSONReader::Read("[\"// ok\\n /* foo */ \"]");
   ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST));
   ListValue* list = static_cast<ListValue*>(root.get());
   ASSERT_EQ(1U, list->GetSize());
@@ -390,11 +388,11 @@
   ASSERT_EQ("// ok\n /* foo */ ", value);
 
   // You can't nest comments.
-  root.reset(JSONReader::Read("/* /* inner */ outer */ [ 1 ]"));
+  root = JSONReader::Read("/* /* inner */ outer */ [ 1 ]");
   ASSERT_FALSE(root.get());
 
   // Not a open comment token.
-  root.reset(JSONReader::Read("/ * * / [1]"));
+  root = JSONReader::Read("/ * * / [1]");
   ASSERT_FALSE(root.get());
 }
 
@@ -415,7 +413,7 @@
 
   JSONFileValueDeserializer deserializer(original_file_path);
   scoped_ptr<Value> root;
-  root.reset(deserializer.Deserialize(NULL, NULL));
+  root = deserializer.Deserialize(NULL, NULL);
 
   ASSERT_TRUE(root.get());
   ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
@@ -463,7 +461,7 @@
 
   JSONFileValueDeserializer deserializer(original_file_path);
   scoped_ptr<Value> root;
-  root.reset(deserializer.Deserialize(NULL, NULL));
+  root = deserializer.Deserialize(NULL, NULL);
   ASSERT_TRUE(root.get());
 
   // Now try writing.
@@ -488,7 +486,7 @@
   ASSERT_TRUE(PathExists(source_file_path));
   JSONFileValueDeserializer deserializer(source_file_path);
   scoped_ptr<Value> root;
-  root.reset(deserializer.Deserialize(NULL, NULL));
+  root = deserializer.Deserialize(NULL, NULL);
   ASSERT_TRUE(root.get());
 }
 
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index d14c92c..abfead8 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -21,12 +21,13 @@
 #endif
 
 // static
-bool JSONWriter::Write(const Value* const node, std::string* json) {
+bool JSONWriter::Write(const Value& node, std::string* json) {
   return WriteWithOptions(node, 0, json);
 }
 
 // static
-bool JSONWriter::WriteWithOptions(const Value* const node, int options,
+bool JSONWriter::WriteWithOptions(const Value& node,
+                                  int options,
                                   std::string* json) {
   json->clear();
   // Is there a better way to estimate the size of the output?
@@ -50,8 +51,8 @@
   DCHECK(json);
 }
 
-bool JSONWriter::BuildJSONString(const Value* const node, size_t depth) {
-  switch (node->GetType()) {
+bool JSONWriter::BuildJSONString(const Value& node, size_t depth) {
+  switch (node.GetType()) {
     case Value::TYPE_NULL: {
       json_string_->append("null");
       return true;
@@ -59,7 +60,7 @@
 
     case Value::TYPE_BOOLEAN: {
       bool value;
-      bool result = node->GetAsBoolean(&value);
+      bool result = node.GetAsBoolean(&value);
       DCHECK(result);
       json_string_->append(value ? "true" : "false");
       return result;
@@ -67,7 +68,7 @@
 
     case Value::TYPE_INTEGER: {
       int value;
-      bool result = node->GetAsInteger(&value);
+      bool result = node.GetAsInteger(&value);
       DCHECK(result);
       json_string_->append(IntToString(value));
       return result;
@@ -75,7 +76,7 @@
 
     case Value::TYPE_DOUBLE: {
       double value;
-      bool result = node->GetAsDouble(&value);
+      bool result = node.GetAsDouble(&value);
       DCHECK(result);
       if (omit_double_type_preservation_ &&
           value <= kint64max &&
@@ -107,7 +108,7 @@
 
     case Value::TYPE_STRING: {
       std::string value;
-      bool result = node->GetAsString(&value);
+      bool result = node.GetAsString(&value);
       DCHECK(result);
       EscapeJSONString(value, true, json_string_);
       return result;
@@ -120,7 +121,7 @@
 
       const ListValue* list = NULL;
       bool first_value_has_been_output = false;
-      bool result = node->GetAsList(&list);
+      bool result = node.GetAsList(&list);
       DCHECK(result);
       for (ListValue::const_iterator it = list->begin(); it != list->end();
            ++it) {
@@ -134,7 +135,7 @@
             json_string_->push_back(' ');
         }
 
-        if (!BuildJSONString(value, depth))
+        if (!BuildJSONString(*value, depth))
           result = false;
 
         first_value_has_been_output = true;
@@ -153,7 +154,7 @@
 
       const DictionaryValue* dict = NULL;
       bool first_value_has_been_output = false;
-      bool result = node->GetAsDictionary(&dict);
+      bool result = node.GetAsDictionary(&dict);
       DCHECK(result);
       for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
            itr.Advance()) {
@@ -176,7 +177,7 @@
         if (pretty_print_)
           json_string_->push_back(' ');
 
-        if (!BuildJSONString(&itr.value(), depth + 1U))
+        if (!BuildJSONString(itr.value(), depth + 1U))
           result = false;
 
         first_value_has_been_output = true;
diff --git a/base/json/json_writer.h b/base/json/json_writer.h
index 9709c7e..5711665 100644
--- a/base/json/json_writer.h
+++ b/base/json/json_writer.h
@@ -38,11 +38,12 @@
   // 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);
+  static bool Write(const Value& node, std::string* json);
 
   // Same as above but with |options| which is a bunch of JSONWriter::Options
   // bitwise ORed together. Return true on success and false on failure.
-  static bool WriteWithOptions(const Value* const node, int options,
+  static bool WriteWithOptions(const Value& node,
+                               int options,
                                std::string* json);
 
  private:
@@ -50,7 +51,7 @@
 
   // Called recursively to build the JSON string. When completed,
   // |json_string_| will contain the JSON.
-  bool BuildJSONString(const Value* const node, size_t depth);
+  bool BuildJSONString(const Value& node, size_t depth);
 
   // Adds space to json_string_ for the indent level.
   void IndentLine(size_t depth);
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
index 5ac2590..a6f1a18 100644
--- a/base/json/json_writer_unittest.cc
+++ b/base/json/json_writer_unittest.cc
@@ -12,47 +12,39 @@
   std::string output_js;
 
   // Test null.
-  EXPECT_TRUE(JSONWriter::Write(Value::CreateNullValue().get(), &output_js));
+  EXPECT_TRUE(JSONWriter::Write(*Value::CreateNullValue(), &output_js));
   EXPECT_EQ("null", output_js);
 
   // Test empty dict.
-  DictionaryValue dict;
-  EXPECT_TRUE(JSONWriter::Write(&dict, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(DictionaryValue(), &output_js));
   EXPECT_EQ("{}", output_js);
 
   // Test empty list.
-  ListValue list;
-  EXPECT_TRUE(JSONWriter::Write(&list, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(ListValue(), &output_js));
   EXPECT_EQ("[]", output_js);
 
   // Test integer values.
-  FundamentalValue int_value(42);
-  EXPECT_TRUE(JSONWriter::Write(&int_value, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(42), &output_js));
   EXPECT_EQ("42", output_js);
 
   // Test boolean values.
-  FundamentalValue bool_value(true);
-  EXPECT_TRUE(JSONWriter::Write(&bool_value, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(true), &output_js));
   EXPECT_EQ("true", output_js);
 
   // Test Real values should always have a decimal or an 'e'.
-  FundamentalValue double_value(1.0);
-  EXPECT_TRUE(JSONWriter::Write(&double_value, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(1.0), &output_js));
   EXPECT_EQ("1.0", output_js);
 
   // Test Real values in the the range (-1, 1) must have leading zeros
-  FundamentalValue double_value2(0.2);
-  EXPECT_TRUE(JSONWriter::Write(&double_value2, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(0.2), &output_js));
   EXPECT_EQ("0.2", output_js);
 
   // Test Real values in the the range (-1, 1) must have leading zeros
-  FundamentalValue double_value3(-0.8);
-  EXPECT_TRUE(JSONWriter::Write(&double_value3, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(-0.8), &output_js));
   EXPECT_EQ("-0.8", output_js);
 
   // Test String values.
-  StringValue string_value("foo");
-  EXPECT_TRUE(JSONWriter::Write(&string_value, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(StringValue("foo"), &output_js));
   EXPECT_EQ("\"foo\"", output_js);
 }
 
@@ -65,17 +57,16 @@
   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(std::move(inner_dict));
   list->Append(make_scoped_ptr(new ListValue()));
   list->AppendBoolean(true);
-  root_dict.Set("list", list.Pass());
+  root_dict.Set("list", std::move(list));
 
   // Test the pretty-printer.
-  EXPECT_TRUE(JSONWriter::Write(&root_dict, &output_js));
+  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));
+  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.
@@ -101,14 +92,14 @@
   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));
+  period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2));
+  EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js));
   EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
 
   DictionaryValue period_dict3;
   period_dict3.SetInteger("a.b", 2);
   period_dict3.SetIntegerWithoutPathExpansion("a.b", 1);
-  EXPECT_TRUE(JSONWriter::Write(&period_dict3, &output_js));
+  EXPECT_TRUE(JSONWriter::Write(period_dict3, &output_js));
   EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
 }
 
@@ -118,9 +109,9 @@
   // Binary values should return errors unless suppressed via the
   // OPTIONS_OMIT_BINARY_VALUES flag.
   scoped_ptr<Value> root(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
-  EXPECT_FALSE(JSONWriter::Write(root.get(), &output_js));
+  EXPECT_FALSE(JSONWriter::Write(*root, &output_js));
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      root.get(), JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+      *root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
   EXPECT_TRUE(output_js.empty());
 
   ListValue binary_list;
@@ -129,9 +120,9 @@
   binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
   binary_list.Append(make_scoped_ptr(new FundamentalValue(2)));
   binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
-  EXPECT_FALSE(JSONWriter::Write(&binary_list, &output_js));
+  EXPECT_FALSE(JSONWriter::Write(binary_list, &output_js));
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      &binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+      binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
   EXPECT_EQ("[5,2]", output_js);
 
   DictionaryValue binary_dict;
@@ -143,9 +134,9 @@
   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_FALSE(JSONWriter::Write(binary_dict, &output_js));
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
-      &binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+      binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
   EXPECT_EQ("{\"b\":5,\"d\":2}", output_js);
 }
 
@@ -155,8 +146,7 @@
   // 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,
+      double_value, JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
       &output_js));
   EXPECT_EQ("10000000000", output_js);
 }
diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc
index a3b0735..3221a3c 100644
--- a/base/json/string_escape.cc
+++ b/base/json/string_escape.cc
@@ -23,7 +23,7 @@
 const uint32 kReplacementCodePoint = 0xFFFD;
 
 // Used below in EscapeSpecialCodePoint().
-COMPILE_ASSERT('<' == 0x3C, less_than_sign_is_0x3c);
+static_assert('<' == 0x3C, "less than sign must be 0x3c");
 
 // Try to escape the |code_point| if it is a known special character. If
 // successful, returns true and appends the escape sequence to |dest|. This
@@ -59,6 +59,14 @@
     case '<':
       dest->append("\\u003C");
       break;
+    // Escape the "Line Separator" and "Paragraph Separator" characters, since
+    // they should be treated like a new line \r or \n.
+    case 0x2028:
+      dest->append("\\u2028");
+      break;
+    case 0x2029:
+      dest->append("\\u2029");
+      break;
     default:
       return false;
   }
@@ -135,7 +143,7 @@
     dest.push_back('"');
 
   for (StringPiece::const_iterator it = str.begin(); it != str.end(); ++it) {
-    ToUnsigned<StringPiece::value_type>::Unsigned c = *it;
+    unsigned char c = *it;
     if (EscapeSpecialCodePoint(c, &dest))
       continue;
 
diff --git a/base/json/string_escape_unittest.cc b/base/json/string_escape_unittest.cc
index 100373f..f7ccafc 100644
--- a/base/json/string_escape_unittest.cc
+++ b/base/json/string_escape_unittest.cc
@@ -21,6 +21,8 @@
     {"b\x0f\x7f\xf0\xff!",  // \xf0\xff is not a valid UTF-8 unit.
         "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"},
     {"c<>d", "c\\u003C>d"},
+    {"Hello\xe2\x80\xa8world", "Hello\\u2028world"},
+    {"\xe2\x80\xa9purple", "\\u2029purple"},
   };
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
@@ -79,6 +81,8 @@
         "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
     {L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"},
     {L"c<>d", "c\\u003C>d"},
+    {L"Hello\u2028world", "Hello\\u2028world"},
+    {L"\u2029purple", "\\u2029purple"},
   };
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
diff --git a/base/linux_util.cc b/base/linux_util.cc
index d6cd504..d94588f 100644
--- a/base/linux_util.cc
+++ b/base/linux_util.cc
@@ -37,7 +37,7 @@
  public:
   // Retrieves the Singleton.
   static LinuxDistroHelper* GetInstance() {
-    return Singleton<LinuxDistroHelper>::get();
+    return base::Singleton<LinuxDistroHelper>::get();
   }
 
   // The simple state machine goes from:
@@ -106,7 +106,7 @@
   argv.push_back("lsb_release");
   argv.push_back("-d");
   std::string output;
-  base::GetAppOutput(CommandLine(argv), &output);
+  GetAppOutput(CommandLine(argv), &output);
   if (output.length() > 0) {
     // lsb_release -d should return: Description:<tab>Distro Info
     const char field[] = "Description:\t";
@@ -124,8 +124,8 @@
 
 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);
+  TrimWhitespaceASCII(distro, TRIM_ALL, &trimmed_distro);
+  strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
 }
 
 pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
diff --git a/base/logging.cc b/base/logging.cc
index c7a8881..650351d 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -7,6 +7,8 @@
 #if defined(OS_WIN)
 #include <io.h>
 #include <windows.h>
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
 typedef HANDLE FileHandle;
 typedef HANDLE MutexHandle;
 // Windows warns on using write().  It prefers _write().
@@ -14,6 +16,8 @@
 // Windows doesn't define STDERR_FILENO.  Define it here.
 #define STDERR_FILENO 2
 #elif defined(OS_MACOSX)
+#include <asl.h>
+#include <CoreFoundation/CoreFoundation.h>
 #include <mach/mach.h>
 #include <mach/mach_time.h>
 #include <mach-o/dyld.h>
@@ -28,10 +32,12 @@
 
 #if defined(OS_POSIX)
 #include <errno.h>
+#include <paths.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #define MAX_PATH PATH_MAX
 typedef FILE* FileHandle;
@@ -54,12 +60,13 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock_impl.h"
 #include "base/threading/platform_thread.h"
 #include "base/vlog.h"
 #if defined(OS_POSIX)
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 #endif
 
 #if defined(OS_ANDROID)
@@ -70,8 +77,8 @@
 
 namespace {
 
-VlogInfo* g_vlog_info = NULL;
-VlogInfo* g_vlog_info_prev = NULL;
+VlogInfo* g_vlog_info = nullptr;
+VlogInfo* g_vlog_info_prev = nullptr;
 
 const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
   "INFO", "WARNING", "ERROR", "FATAL" };
@@ -82,9 +89,9 @@
   return "UNKNOWN";
 }
 
-int min_log_level = 0;
+int g_min_log_level = 0;
 
-LoggingDestination logging_destination = LOG_DEFAULT;
+LoggingDestination g_logging_destination = LOG_DEFAULT;
 
 // For LOG_ERROR and above, always print to stderr.
 const int kAlwaysPrintErrorLevel = LOG_ERROR;
@@ -97,25 +104,25 @@
 #else
 typedef std::string PathString;
 #endif
-PathString* log_file_name = NULL;
+PathString* g_log_file_name = nullptr;
 
-// this file is lazily opened and the handle may be NULL
-FileHandle log_file = NULL;
+// This file is lazily opened and the handle may be nullptr
+FileHandle g_log_file = nullptr;
 
-// 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;
+// What should be prepended to each message?
+bool g_log_process_id = false;
+bool g_log_thread_id = false;
+bool g_log_timestamp = true;
+bool g_log_tickcount = false;
 
 // Should we pop up fatal debug messages in a dialog?
 bool show_error_dialogs = false;
 
 // An assert handler override specified by the client to be called instead of
 // the debug message dialog and process termination.
-LogAssertHandlerFunction log_assert_handler = NULL;
+LogAssertHandlerFunction log_assert_handler = nullptr;
 // A log message handler that gets notified of every log message we process.
-LogMessageHandlerFunction log_message_handler = NULL;
+LogMessageHandlerFunction log_message_handler = nullptr;
 
 // Helper functions to wrap platform differences.
 
@@ -162,7 +169,7 @@
 #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);
+  GetModuleFileName(nullptr, module_name, MAX_PATH);
 
   PathString log_name = module_name;
   PathString::size_type last_backslash = log_name.rfind('\\', log_name.size());
@@ -176,6 +183,9 @@
 #endif
 }
 
+// We don't need locks on Windows for atomically appending to files. The OS
+// provides this functionality.
+#if !defined(OS_WIN)
 // This class acts as a wrapper for locking the logging files.
 // LoggingLock::Init() should be called from the main thread before any logging
 // is done. Then whenever logging, be sure to have a local LoggingLock
@@ -196,48 +206,17 @@
     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 {
+    if (lock_log_file != LOCK_LOG_FILE)
       log_lock = new base::internal::LockImpl();
-    }
+
     initialized = true;
   }
 
  private:
   static void LockLogging() {
     if (lock_log_file == LOCK_LOG_FILE) {
-#if defined(OS_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)
+#if defined(OS_POSIX)
       pthread_mutex_lock(&log_mutex);
 #endif
     } else {
@@ -248,9 +227,7 @@
 
   static void UnlockLogging() {
     if (lock_log_file == LOCK_LOG_FILE) {
-#if defined(OS_WIN)
-      ReleaseMutex(log_mutex);
-#elif defined(OS_POSIX)
+#if defined(OS_POSIX)
       pthread_mutex_unlock(&log_mutex);
 #endif
     } else {
@@ -265,9 +242,7 @@
 
   // 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)
+#if defined(OS_POSIX)
   static pthread_mutex_t log_mutex;
 #endif
 
@@ -278,49 +253,58 @@
 // static
 bool LoggingLock::initialized = false;
 // static
-base::internal::LockImpl* LoggingLock::log_lock = NULL;
+base::internal::LockImpl* LoggingLock::log_lock = nullptr;
 // static
 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
 
-#if defined(OS_WIN)
-// static
-MutexHandle LoggingLock::log_mutex = NULL;
-#elif defined(OS_POSIX)
+#if defined(OS_POSIX)
 pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
 #endif
 
-// Called by logging functions to ensure that debug_file is initialized
+#endif  // OS_WIN
+
+// Called by logging functions to ensure that |g_log_file| is initialized
 // and can be used for writing. Returns false if the file could not be
-// initialized. debug_file will be NULL in this case.
+// initialized. |g_log_file| will be nullptr in this case.
 bool InitializeLogFileHandle() {
-  if (log_file)
+  if (g_log_file)
     return true;
 
-  if (!log_file_name) {
+  if (!g_log_file_name) {
     // Nobody has called InitLogging to specify a debug log file, so here we
     // initialize the log file name to a default.
-    log_file_name = new PathString(GetDefaultLogFile());
+    g_log_file_name = new PathString(GetDefaultLogFile());
   }
 
-  if ((logging_destination & LOG_TO_FILE) != 0) {
+  if ((g_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) {
+    // The FILE_APPEND_DATA access mask ensures that the file is atomically
+    // appended to across accesses from multiple threads.
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364399(v=vs.85).aspx
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
+    g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
+                            OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+    if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
       // 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;
+      base::FilePath file_path;
+      if (!base::GetCurrentDirectory(&file_path))
+        return false;
+
+      *g_log_file_name = file_path.Append(
+          FILE_PATH_LITERAL("debug.log")).value();
+
+      g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
+                              FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
+                              OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+      if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
+        g_log_file = nullptr;
         return false;
       }
     }
-    SetFilePointer(log_file, 0, 0, FILE_END);
 #elif defined(OS_POSIX)
-    log_file = fopen(log_file_name->c_str(), "a");
-    if (log_file == NULL)
+    g_log_file = fopen(g_log_file_name->c_str(), "a");
+    if (g_log_file == nullptr)
       return false;
 #endif
   }
@@ -337,18 +321,18 @@
 }
 
 void CloseLogFileUnlocked() {
-  if (!log_file)
+  if (!g_log_file)
     return;
 
-  CloseFile(log_file);
-  log_file = NULL;
+  CloseFile(g_log_file);
+  g_log_file = nullptr;
 }
 
 }  // namespace
 
 LoggingSettings::LoggingSettings()
     : logging_dest(LOG_DEFAULT),
-      log_file(NULL),
+      log_file(nullptr),
       lock_log(LOCK_LOG_FILE),
       delete_old(APPEND_TO_OLD_LOG_FILE) {}
 
@@ -358,11 +342,11 @@
   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
+  // 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
+    // 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);
@@ -371,37 +355,39 @@
     g_vlog_info =
         new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
                      command_line->GetSwitchValueASCII(switches::kVModule),
-                     &min_log_level);
+                     &g_min_log_level);
   }
 
-  logging_destination = settings.logging_dest;
+  g_logging_destination = settings.logging_dest;
 
   // ignore file options unless logging to file is set.
-  if ((logging_destination & LOG_TO_FILE) == 0)
+  if ((g_logging_destination & LOG_TO_FILE) == 0)
     return true;
 
+#if !defined(OS_WIN)
   LoggingLock::Init(settings.lock_log, settings.log_file);
   LoggingLock logging_lock;
+#endif
 
   // Calling InitLogging twice or after some log call has already opened the
   // default log file will re-initialize to the new options.
   CloseLogFileUnlocked();
 
-  if (!log_file_name)
-    log_file_name = new PathString();
-  *log_file_name = settings.log_file;
+  if (!g_log_file_name)
+    g_log_file_name = new PathString();
+  *g_log_file_name = settings.log_file;
   if (settings.delete_old == DELETE_OLD_LOG_FILE)
-    DeleteFilePath(*log_file_name);
+    DeleteFilePath(*g_log_file_name);
 
   return InitializeLogFileHandle();
 }
 
 void SetMinLogLevel(int level) {
-  min_log_level = std::min(LOG_FATAL, level);
+  g_min_log_level = std::min(LOG_FATAL, level);
 }
 
 int GetMinLogLevel() {
-  return min_log_level;
+  return g_min_log_level;
 }
 
 int GetVlogVerbosity() {
@@ -410,8 +396,8 @@
 
 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).
+  // Note: |g_vlog_info| may change on a different thread during startup
+  // (but will always be valid or nullptr).
   VlogInfo* vlog_info = g_vlog_info;
   return vlog_info ?
       vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) :
@@ -420,10 +406,10 @@
 
 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;
+  g_log_process_id = enable_process_id;
+  g_log_thread_id = enable_thread_id;
+  g_log_timestamp = enable_timestamp;
+  g_log_tickcount = enable_tickcount;
 }
 
 void SetShowErrorDialogs(bool enable_dialogs) {
@@ -468,42 +454,12 @@
     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);
-  }
+  MessageBoxW(nullptr, base::UTF8ToUTF16(str).c_str(), L"Fatal error",
+              MB_OK | MB_ICONHAND | MB_TOPMOST);
 #else
   // We intentionally don't implement a dialog on other platforms.
   // You can just look at stderr.
-#endif
+#endif  // defined(OS_WIN)
 }
 #endif  // !defined(NDEBUG)
 
@@ -521,6 +477,12 @@
   Init(file, line);
 }
 
+LogMessage::LogMessage(const char* file, int line, const char* condition)
+    : severity_(LOG_FATAL), file_(file), line_(line) {
+  Init(file, line);
+  stream_ << "Check failed: " << condition << ". ";
+}
+
 LogMessage::LogMessage(const char* file, int line, std::string* result)
     : severity_(LOG_FATAL), file_(file), line_(line) {
   Init(file, line);
@@ -537,9 +499,9 @@
 }
 
 LogMessage::~LogMessage() {
-#if !defined(NDEBUG) && !defined(OS_NACL) && !defined(__UCLIBC__)
-  if (severity_ == LOG_FATAL) {
-    // Include a stack trace on a fatal.
+#if !defined(OFFICIAL_BUILD) && !defined(OS_NACL) && !defined(__UCLIBC__)
+  if (severity_ == LOG_FATAL && !base::debug::BeingDebugged()) {
+    // Include a stack trace on a fatal, unless a debugger is attached.
     base::debug::StackTrace trace;
     stream_ << std::endl;  // Newline to separate from log message.
     trace.OutputToStream(&stream_);
@@ -556,9 +518,124 @@
     return;
   }
 
-  if ((logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
+  if ((g_logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
 #if defined(OS_WIN)
     OutputDebugStringA(str_newline.c_str());
+#elif defined(OS_MACOSX)
+    // In LOG_TO_SYSTEM_DEBUG_LOG mode, log messages are always written to
+    // stderr. If stderr is /dev/null, also log via ASL (Apple System Log). If
+    // there's something weird about stderr, assume that log messages are going
+    // nowhere and log via ASL too. Messages logged via ASL show up in
+    // Console.app.
+    //
+    // Programs started by launchd, as UI applications normally are, have had
+    // stderr connected to /dev/null since OS X 10.8. Prior to that, stderr was
+    // a pipe to launchd, which logged what it received (see log_redirect_fd in
+    // 10.7.5 launchd-392.39/launchd/src/launchd_core_logic.c).
+    //
+    // Another alternative would be to determine whether stderr is a pipe to
+    // launchd and avoid logging via ASL only in that case. See 10.7.5
+    // CF-635.21/CFUtilities.c also_do_stderr(). This would result in logging to
+    // both stderr and ASL even in tests, where it's undesirable to log to the
+    // system log at all.
+    //
+    // Note that the ASL client by default discards messages whose levels are
+    // below ASL_LEVEL_NOTICE. It's possible to change that with
+    // asl_set_filter(), but this is pointless because syslogd normally applies
+    // the same filter.
+    const bool log_via_asl = []() {
+      struct stat stderr_stat;
+      if (fstat(fileno(stderr), &stderr_stat) == -1) {
+        return true;
+      }
+      if (!S_ISCHR(stderr_stat.st_mode)) {
+        return false;
+      }
+
+      struct stat dev_null_stat;
+      if (stat(_PATH_DEVNULL, &dev_null_stat) == -1) {
+        return true;
+      }
+
+      return !S_ISCHR(dev_null_stat.st_mode) ||
+             stderr_stat.st_rdev == dev_null_stat.st_rdev;
+    }();
+
+    if (log_via_asl) {
+      // Log roughly the same way that CFLog() and NSLog() would. See 10.10.5
+      // CF-1153.18/CFUtilities.c __CFLogCString().
+      //
+      // The ASL facility is set to the main bundle ID if available. Otherwise,
+      // "com.apple.console" is used.
+      CFBundleRef main_bundle = CFBundleGetMainBundle();
+      CFStringRef main_bundle_id_cf =
+          main_bundle ? CFBundleGetIdentifier(main_bundle) : nullptr;
+      std::string asl_facility =
+          main_bundle_id_cf ? base::SysCFStringRefToUTF8(main_bundle_id_cf)
+                            : std::string("com.apple.console");
+
+      class ASLClient {
+       public:
+        explicit ASLClient(const std::string& asl_facility)
+            : client_(asl_open(nullptr,
+                               asl_facility.c_str(),
+                               ASL_OPT_NO_DELAY)) {}
+        ~ASLClient() { asl_close(client_); }
+
+        aslclient get() const { return client_; }
+
+       private:
+        aslclient client_;
+        DISALLOW_COPY_AND_ASSIGN(ASLClient);
+      } asl_client(asl_facility);
+
+      class ASLMessage {
+       public:
+        ASLMessage() : message_(asl_new(ASL_TYPE_MSG)) {}
+        ~ASLMessage() { asl_free(message_); }
+
+        aslmsg get() const { return message_; }
+
+       private:
+        aslmsg message_;
+        DISALLOW_COPY_AND_ASSIGN(ASLMessage);
+      } asl_message;
+
+      // By default, messages are only readable by the admin group. Explicitly
+      // make them readable by the user generating the messages.
+      char euid_string[12];
+      snprintf(euid_string, arraysize(euid_string), "%d", geteuid());
+      asl_set(asl_message.get(), ASL_KEY_READ_UID, euid_string);
+
+      // Map Chrome log severities to ASL log levels.
+      const char* const asl_level_string = [](LogSeverity severity) {
+        // ASL_LEVEL_* are ints, but ASL needs equivalent strings. This
+        // non-obvious two-step macro trick achieves what's needed.
+        // https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
+#define ASL_LEVEL_STR(level) ASL_LEVEL_STR_X(level)
+#define ASL_LEVEL_STR_X(level) #level
+        switch (severity) {
+          case LOG_INFO:
+            return ASL_LEVEL_STR(ASL_LEVEL_INFO);
+          case LOG_WARNING:
+            return ASL_LEVEL_STR(ASL_LEVEL_WARNING);
+          case LOG_ERROR:
+            return ASL_LEVEL_STR(ASL_LEVEL_ERR);
+          case LOG_FATAL:
+            return ASL_LEVEL_STR(ASL_LEVEL_CRIT);
+          default:
+            return severity < 0 ? ASL_LEVEL_STR(ASL_LEVEL_DEBUG)
+                                : ASL_LEVEL_STR(ASL_LEVEL_NOTICE);
+        }
+#undef ASL_LEVEL_STR
+#undef ASL_LEVEL_STR_X
+      }(severity_);
+      asl_set(asl_message.get(), ASL_KEY_LEVEL, asl_level_string);
+
+      asl_set(asl_message.get(), ASL_KEY_MSG, str_newline.c_str());
+
+      asl_send(asl_client.get(), asl_message.get());
+    }
 #elif defined(OS_ANDROID)
     android_LogPriority priority =
         (severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
@@ -589,7 +666,7 @@
   }
 
   // write to log file
-  if ((logging_destination & LOG_TO_FILE) != 0) {
+  if ((g_logging_destination & LOG_TO_FILE) != 0) {
     // We can have multiple threads and/or processes, so try to prevent them
     // from clobbering each other's writes.
     // If the client app did not call InitLogging, and the lock has not
@@ -597,21 +674,22 @@
     // 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);
+#if !defined(OS_WIN)
+    LoggingLock::Init(LOCK_LOG_FILE, nullptr);
     LoggingLock logging_lock;
+#endif
     if (InitializeLogFileHandle()) {
 #if defined(OS_WIN)
-      SetFilePointer(log_file, 0, 0, SEEK_END);
       DWORD num_written;
-      WriteFile(log_file,
+      WriteFile(g_log_file,
                 static_cast<const void*>(str_newline.c_str()),
                 static_cast<DWORD>(str_newline.length()),
                 &num_written,
-                NULL);
+                nullptr);
 #else
       ignore_result(fwrite(
-          str_newline.data(), str_newline.size(), 1, log_file));
-      fflush(log_file);
+          str_newline.data(), str_newline.size(), 1, g_log_file));
+      fflush(g_log_file);
 #endif
     }
   }
@@ -633,7 +711,11 @@
       // information, and displaying message boxes when the application is
       // hosed can cause additional problems.
 #ifndef NDEBUG
-      DisplayDebugMessageInDialog(stream_.str());
+      if (!base::debug::BeingDebugged()) {
+        // Displaying a dialog is unnecessary when debugging and can complicate
+        // debugging.
+        DisplayDebugMessageInDialog(stream_.str());
+      }
 #endif
       // Crash the process to generate a dump.
       base::debug::BreakDebugger();
@@ -651,12 +733,12 @@
   // TODO(darin): It might be nice if the columns were fixed width.
 
   stream_ <<  '[';
-  if (log_process_id)
+  if (g_log_process_id)
     stream_ << CurrentProcessId() << ':';
-  if (log_thread_id)
+  if (g_log_thread_id)
     stream_ << base::PlatformThread::CurrentId() << ':';
-  if (log_timestamp) {
-    time_t t = time(NULL);
+  if (g_log_timestamp) {
+    time_t t = time(nullptr);
     struct tm local_time = {0};
 #ifdef _MSC_VER
     localtime_s(&local_time, &t);
@@ -673,7 +755,7 @@
             << std::setw(2) << tm_time->tm_sec
             << ':';
   }
-  if (log_tickcount)
+  if (g_log_tickcount)
     stream_ << TickCount() << ':';
   if (severity_ >= 0)
     stream_ << log_severity_name(severity_);
@@ -707,8 +789,8 @@
   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);
+  DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf,
+                             arraysize(msgbuf), nullptr);
   if (len) {
     // Messages returned by system end with line breaks.
     return base::CollapseWhitespaceASCII(msgbuf, true) +
@@ -719,11 +801,11 @@
 }
 #elif defined(OS_POSIX)
 BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) {
-  return safe_strerror(error_code);
+  return base::safe_strerror(error_code);
 }
 #else
 #error Not implemented
-#endif
+#endif  // defined(OS_WIN)
 
 
 #if defined(OS_WIN)
@@ -754,15 +836,17 @@
 ErrnoLogMessage::~ErrnoLogMessage() {
   stream() << ": " << SystemErrorCodeToString(err_);
 }
-#endif  // OS_WIN
+#endif  // defined(OS_WIN)
 
 void CloseLogFile() {
+#if !defined(OS_WIN)
   LoggingLock logging_lock;
+#endif
   CloseLogFileUnlocked();
 }
 
 void RawLog(int level, const char* message) {
-  if (level >= min_log_level) {
+  if (level >= g_min_log_level) {
     size_t bytes_written = 0;
     const size_t message_len = strlen(message);
     int rv;
@@ -796,13 +880,22 @@
 #undef write
 
 #if defined(OS_WIN)
+bool IsLoggingToFileEnabled() {
+  return g_logging_destination & LOG_TO_FILE;
+}
+
 std::wstring GetLogFileFullPath() {
-  if (log_file_name)
-    return *log_file_name;
+  if (g_log_file_name)
+    return *g_log_file_name;
   return std::wstring();
 }
 #endif
 
+BASE_EXPORT void LogErrorNotReached(const char* file, int line) {
+  LogMessage(file, line, LOG_ERROR).stream()
+      << "NOTREACHED() hit.";
+}
+
 }  // namespace logging
 
 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) {
diff --git a/base/logging.h b/base/logging.h
index cc0a5aa..a78b786 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -426,6 +426,21 @@
 #define EAT_STREAM_PARAMETERS                                           \
   true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
 
+// Captures the result of a CHECK_EQ (for example) and facilitates testing as a
+// boolean.
+class CheckOpResult {
+ public:
+  // |message| must be null if and only if the check failed.
+  CheckOpResult(std::string* message) : message_(message) {}
+  // Returns true if the check succeeded.
+  operator bool() const { return !message_; }
+  // Returns the message.
+  std::string* message() { return message_; }
+
+ private:
+  std::string* message_;
+};
+
 // CHECK dies with a fatal error if condition is not true.  It is *not*
 // controlled by NDEBUG, so the check will be executed regardless of
 // compilation mode.
@@ -436,7 +451,7 @@
 #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.
+// bloat for official release builds (except Android).
 
 // TODO(akalin): This would be more valuable if there were some way to
 // remove BreakDebugger() from the backtrace, perhaps by turning it
@@ -470,9 +485,10 @@
 
 #else  // _PREFAST_
 
-#define CHECK(condition)                       \
-  LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
-  << "Check failed: " #condition ". "
+// Do as much work as possible out of line to reduce inline code size.
+#define CHECK(condition)                                                    \
+  LAZY_STREAM(logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
+              !(condition))
 
 #define PCHECK(condition)                       \
   LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
@@ -482,14 +498,18 @@
 
 // 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()
+// The 'switch' is used to prevent the 'else' from being ambiguous when the
+// macro is used in an 'if' clause such as:
+// if (a == 1)
+//   CHECK_EQ(2, a);
+#define CHECK_OP(name, op, val1, val2)                                         \
+  switch (0) case 0: default:                                                  \
+  if (logging::CheckOpResult true_if_passed =                                  \
+      logging::Check##name##Impl((val1), (val2),                               \
+                                 #val1 " " #op " " #val2))                     \
+   ;                                                                           \
+  else                                                                         \
+    logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
 
 #endif
 
@@ -551,7 +571,6 @@
 #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
@@ -665,12 +684,20 @@
 
 // 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()
+// The 'switch' is used to prevent the 'else' from being ambiguous when the
+// macro is used in an 'if' clause such as:
+// if (a == 1)
+//   DCHECK_EQ(2, a);
+#define DCHECK_OP(name, op, val1, val2)                               \
+  switch (0) case 0: default:                                         \
+  if (logging::CheckOpResult true_if_passed =                         \
+      DCHECK_IS_ON() ?                                                \
+      logging::Check##name##Impl((val1), (val2),                      \
+                                 #val1 " " #op " " #val2) : nullptr)  \
+   ;                                                                  \
+  else                                                                \
+    logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK,    \
+                        true_if_passed.message()).stream()
 
 // Equality/Inequality checks - compare two values, and log a
 // LOG_DCHECK message including the two values when the result is not
@@ -697,11 +724,14 @@
 #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__ << ". "
+// Implement logging of NOTREACHED() as a dedicated function to get function
+// call overhead down to a minimum.
+void LogErrorNotReached(const char* file, int line);
+#define NOTREACHED()                                       \
+  true ? ::logging::LogErrorNotReached(__FILE__, __LINE__) \
+       : EAT_STREAM_PARAMETERS
 #else
 #define NOTREACHED() DCHECK(false)
 #endif
@@ -723,6 +753,9 @@
   // Used for LOG(severity).
   LogMessage(const char* file, int line, LogSeverity severity);
 
+  // Used for CHECK().  Implied severity = LOG_FATAL.
+  LogMessage(const char* file, int line, const char* condition);
+
   // Used for CHECK_EQ(), etc. Takes ownership of the given string.
   // Implied severity = LOG_FATAL.
   LogMessage(const char* file, int line, std::string* result);
@@ -771,7 +804,7 @@
 
 // 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) {
+inline void LogAtLevel(int log_level, const std::string& msg) {
   LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
 }
 
@@ -857,6 +890,9 @@
   } while (0)
 
 #if defined(OS_WIN)
+// Returns true if logging to file is enabled.
+BASE_EXPORT bool IsLoggingToFileEnabled();
+
 // Returns the default log file path.
 BASE_EXPORT std::wstring GetLogFileFullPath();
 #endif
@@ -916,9 +952,9 @@
 #define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
 #elif NOTIMPLEMENTED_POLICY == 1
 // TODO, figure out how to generate a warning
-#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
 #elif NOTIMPLEMENTED_POLICY == 2
-#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
 #elif NOTIMPLEMENTED_POLICY == 3
 #define NOTIMPLEMENTED() NOTREACHED()
 #elif NOTIMPLEMENTED_POLICY == 4
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc
index 8b9701a..e061942 100644
--- a/base/logging_unittest.cc
+++ b/base/logging_unittest.cc
@@ -234,6 +234,30 @@
   DCHECK_EQ(some_variable, 1) << "test";
 }
 
+TEST_F(LoggingTest, DCheckEqStatements) {
+  bool reached = false;
+  if (false)
+    DCHECK_EQ(false, true);           // Unreached.
+  else
+    DCHECK_EQ(true, reached = true);  // Reached, passed.
+  ASSERT_EQ(DCHECK_IS_ON() ? true : false, reached);
+
+  if (false)
+    DCHECK_EQ(false, true);           // Unreached.
+}
+
+TEST_F(LoggingTest, CheckEqStatements) {
+  bool reached = false;
+  if (false)
+    CHECK_EQ(false, true);           // Unreached.
+  else
+    CHECK_EQ(true, reached = true);  // Reached, passed.
+  ASSERT_TRUE(reached);
+
+  if (false)
+    CHECK_EQ(false, true);           // Unreached.
+}
+
 // Test that defining an operator<< for a type in a namespace doesn't prevent
 // other code in that namespace from calling the operator<<(ostream, wstring)
 // defined by logging.h. This can fail if operator<<(ostream, wstring) can't be
diff --git a/base/logging_win.cc b/base/logging_win.cc
index 53cc37c..319ae8a 100644
--- a/base/logging_win.cc
+++ b/base/logging_win.cc
@@ -18,8 +18,8 @@
 }
 
 LogEventProvider* LogEventProvider::GetInstance() {
-  return Singleton<LogEventProvider,
-                   StaticMemorySingletonTraits<LogEventProvider> >::get();
+  return base::Singleton<LogEventProvider, base::StaticMemorySingletonTraits<
+                                               LogEventProvider>>::get();
 }
 
 bool LogEventProvider::LogMessage(logging::LogSeverity severity,
diff --git a/base/logging_win.h b/base/logging_win.h
index aa48e22..de34a64 100644
--- a/base/logging_win.h
+++ b/base/logging_win.h
@@ -12,8 +12,10 @@
 #include "base/win/event_trace_provider.h"
 #include "base/logging.h"
 
+namespace base {
 template <typename Type>
 struct StaticMemorySingletonTraits;
+}  // namespace base
 
 namespace logging {
 
@@ -71,7 +73,7 @@
   // restored in OnEventsDisabled.
   logging::LogSeverity old_log_level_;
 
-  friend struct StaticMemorySingletonTraits<LogEventProvider>;
+  friend struct base::StaticMemorySingletonTraits<LogEventProvider>;
   DISALLOW_COPY_AND_ASSIGN(LogEventProvider);
 };
 
diff --git a/base/mac/OWNERS b/base/mac/OWNERS
index 4aba972..093a9c8 100644
--- a/base/mac/OWNERS
+++ b/base/mac/OWNERS
@@ -2,13 +2,5 @@
 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
+# developers in general.
+per-file sdk_forward_declarations.*=file://chrome/browser/ui/cocoa/OWNERS
diff --git a/base/mac/authorization_util.mm b/base/mac/authorization_util.mm
index 1dfd5a0..a97796e 100644
--- a/base/mac/authorization_util.mm
+++ b/base/mac/authorization_util.mm
@@ -50,8 +50,8 @@
   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."
+  // The OS will dispay |prompt| along with a sentence asking the user to type
+  // the "password to allow this."
   NSString* prompt_ns = base::mac::CFToNSCast(prompt);
   const char* prompt_c = [prompt_ns UTF8String];
   size_t prompt_length = prompt_c ? strlen(prompt_c) : 0;
diff --git a/base/mac/bind_objc_block_unittest.mm b/base/mac/bind_objc_block_unittest.mm
index 5d15eba..c0e690c 100644
--- a/base/mac/bind_objc_block_unittest.mm
+++ b/base/mac/bind_objc_block_unittest.mm
@@ -6,8 +6,8 @@
 
 #include <string>
 
-#include "base/callback.h"
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/base/mac/call_with_eh_frame.cc b/base/mac/call_with_eh_frame.cc
new file mode 100644
index 0000000..8ea6f75
--- /dev/null
+++ b/base/mac/call_with_eh_frame.cc
@@ -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.
+
+#include "base/mac/call_with_eh_frame.h"
+
+#include <unwind.h>
+
+#include "build/build_config.h"
+
+namespace base {
+namespace mac {
+
+_Unwind_Reason_Code CxxPersonalityRoutine(
+    int version,
+    _Unwind_Action actions,
+    uint64_t exceptionClass,
+    struct _Unwind_Exception* exceptionObject,
+    struct _Unwind_Context* context) {
+  // Tell libunwind that this is the end of the stack. When it encounters the
+  // CallWithEHFrame, it will stop searching for an exception handler. The
+  // result is that no exception handler has been found higher on the stack,
+  // and any that are lower on the stack (e.g. in CFRunLoopRunSpecific), will
+  // now be skipped. Since this is reporting the end of the stack, and no
+  // exception handler will have been found, std::terminate() will be called.
+  return _URC_END_OF_STACK;
+}
+
+#if defined(OS_IOS)
+// No iOS assembly implementation exists, so just call the block directly.
+void CallWithEHFrame(void (^block)(void)) {
+  block();
+}
+#endif
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/call_with_eh_frame.h b/base/mac/call_with_eh_frame.h
new file mode 100644
index 0000000..1f7d5e0
--- /dev/null
+++ b/base/mac/call_with_eh_frame.h
@@ -0,0 +1,26 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_CALL_WITH_EH_FRAME_H_
+#define BASE_MAC_CALL_WITH_EH_FRAME_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// Invokes the specified block in a stack frame with a special exception
+// handler. This function creates an exception handling stack frame that
+// specifies a custom C++ exception personality routine, which terminates the
+// search for an exception handler at this frame.
+//
+// The purpose of this function is to prevent a try/catch statement in system
+// libraries, acting as a global exception handler, from handling exceptions
+// in such a way that disrupts the generation of useful stack traces.
+void BASE_EXPORT CallWithEHFrame(void (^block)(void));
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_CALL_WITH_EH_FRAME_H_
diff --git a/base/mac/call_with_eh_frame_asm.S b/base/mac/call_with_eh_frame_asm.S
new file mode 100644
index 0000000..0e399cf
--- /dev/null
+++ b/base/mac/call_with_eh_frame_asm.S
@@ -0,0 +1,89 @@
+// Copyright 2015 The Chromium 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::mac::CallWithEHFrame(void () block_pointer)
+#define CALL_WITH_EH_FRAME __ZN4base3mac15CallWithEHFrameEU13block_pointerFvvE
+
+  .section __TEXT,__text,regular,pure_instructions
+#if !defined(COMPONENT_BUILD)
+  .private_extern CALL_WITH_EH_FRAME
+#endif
+  .globl CALL_WITH_EH_FRAME
+  .align 4
+CALL_WITH_EH_FRAME:
+
+  .cfi_startproc
+
+  // Configure the C++ exception handler personality routine. Normally the
+  // compiler would emit ___gxx_personality_v0 here. The purpose of this
+  // function is to use a custom personality routine.
+  .cfi_personality 155, __ZN4base3mac21CxxPersonalityRoutineEi14_Unwind_ActionyP17_Unwind_ExceptionP15_Unwind_Context
+  .cfi_lsda 16, CallWithEHFrame_exception_table
+
+Lfunction_start:
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+
+  // Load the function pointer from the block descriptor.
+  movq 16(%rdi), %rax
+
+  // Execute the block in the context of a C++ try{}.
+Ltry_start:
+  callq *%rax
+Ltry_end:
+  popq %rbp
+  ret
+
+  // Landing pad for the exception handler. This should never be called, since
+  // the personality routine will stop the search for an exception handler,
+  // which will cause the runtime to invoke the default terminate handler.
+Lcatch:
+  movq %rax, %rdi
+  callq ___cxa_begin_catch  // The ABI requires a call to the catch handler.
+  ud2  // In the event this is called, make it fatal.
+
+Lfunction_end:
+  .cfi_endproc
+
+// The C++ exception table that is used to identify this frame as an
+// exception handler. See http://llvm.org/docs/ExceptionHandling.html and
+// http://mentorembedded.github.io/cxx-abi/exceptions.pdf.
+  .section __TEXT,__gcc_except_tab
+  .align 2
+CallWithEHFrame_exception_table:
+  .byte 255  // DW_EH_PE_omit
+  .byte 155  // DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4
+  .asciz "\242\200\200"  // LE int128 for the number of bytes in this table.
+  .byte 3  // DW_EH_PE_udata4
+  .byte 26  // Callsite table length.
+
+// First callsite.
+CS1_begin = Ltry_start - Lfunction_start
+  .long CS1_begin
+CS1_end = Ltry_end - Ltry_start
+  .long CS1_end
+
+// First landing pad.
+LP1 = Lcatch - Lfunction_start
+  .long LP1
+  .byte 1  // Action record.
+
+// Second callsite.
+CS2_begin = Ltry_end - Lfunction_start
+  .long CS2_begin
+CS2_end = Lfunction_end - Ltry_end
+  .long CS2_end
+
+// Second landing pad (none).
+  .long 0
+  .byte 0  // No action.
+
+// Action table.
+  .byte 1  // Action record 1.
+  .byte 0  // No further action to take.
+  .long 0  // No type filter for this catch(){} clause.
+  .align 2
diff --git a/base/mac/call_with_eh_frame_unittest.mm b/base/mac/call_with_eh_frame_unittest.mm
new file mode 100644
index 0000000..4dad822
--- /dev/null
+++ b/base/mac/call_with_eh_frame_unittest.mm
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/call_with_eh_frame.h"
+
+#import <Foundation/Foundation.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace mac {
+namespace {
+
+class CallWithEHFrameTest : public testing::Test {
+ protected:
+  void ThrowException() {
+    @throw [NSException exceptionWithName:@"TestException"
+                                   reason:@"Testing exceptions"
+                                 userInfo:nil];
+  }
+};
+
+// Catching from within the EHFrame is allowed.
+TEST_F(CallWithEHFrameTest, CatchExceptionHigher) {
+  bool __block saw_exception = false;
+  base::mac::CallWithEHFrame(^{
+    @try {
+      ThrowException();
+    } @catch (NSException* exception) {
+      saw_exception = true;
+    }
+  });
+  EXPECT_TRUE(saw_exception);
+}
+
+// Trying to catch an exception outside the EHFrame is blocked.
+TEST_F(CallWithEHFrameTest, CatchExceptionLower) {
+  auto catch_exception_lower = ^{
+    bool saw_exception = false;
+    @try {
+      base::mac::CallWithEHFrame(^{
+        ThrowException();
+      });
+    } @catch (NSException* exception) {
+      saw_exception = true;
+    }
+    ASSERT_FALSE(saw_exception);
+  };
+  EXPECT_DEATH(catch_exception_lower(), "");
+}
+
+}  // namespace
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h
index 353ed7c..6e8505d 100644
--- a/base/mac/foundation_util.h
+++ b/base/mac/foundation_util.h
@@ -373,6 +373,14 @@
 // Converts |str| to a FilePath. Returns an empty path if |str| is nil.
 BASE_EXPORT FilePath NSStringToFilePath(NSString* str);
 
+#if defined(__OBJC__)
+// Converts |range| to an NSRange, returning the new range in |range_out|.
+// Returns true if conversion was successful, false if the values of |range|
+// could not be converted to NSUIntegers.
+BASE_EXPORT bool CFRangeToNSRange(CFRange range,
+                                  NSRange* range_out) WARN_UNUSED_RESULT;
+#endif  // defined(__OBJC__)
+
 }  // namespace mac
 }  // namespace base
 
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
index 27d6e7c..bd5d514 100644
--- a/base/mac/foundation_util.mm
+++ b/base/mac/foundation_util.mm
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_logging.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 
 #if !defined(OS_IOS)
@@ -430,6 +431,19 @@
   return FilePath([str fileSystemRepresentation]);
 }
 
+bool CFRangeToNSRange(CFRange range, NSRange* range_out) {
+  if (base::IsValueInRangeForNumericType<decltype(range_out->location)>(
+          range.location) &&
+      base::IsValueInRangeForNumericType<decltype(range_out->length)>(
+          range.length) &&
+      base::IsValueInRangeForNumericType<decltype(range_out->location)>(
+          range.location + range.length)) {
+    *range_out = NSMakeRange(range.location, range.length);
+    return true;
+  }
+  return false;
+}
+
 }  // namespace mac
 }  // namespace base
 
diff --git a/base/mac/foundation_util_unittest.mm b/base/mac/foundation_util_unittest.mm
index e60a0f6..69d5b1f 100644
--- a/base/mac/foundation_util_unittest.mm
+++ b/base/mac/foundation_util_unittest.mm
@@ -281,8 +281,8 @@
   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);
+  static_assert(arraysize(keys) == arraysize(values),
+                "keys and values arrays must have the same size");
 
   ScopedCFTypeRef<CFDictionaryRef> test_dict(
       CFDictionaryCreate(kCFAllocatorDefault,
@@ -317,6 +317,18 @@
   EXPECT_EQ(FilePath("/a/b"), NSStringToFilePath(@"/a/b"));
 }
 
+TEST(FoundationUtilTest, CFRangeToNSRange) {
+  NSRange range_out;
+  EXPECT_TRUE(CFRangeToNSRange(CFRangeMake(10, 5), &range_out));
+  EXPECT_EQ(10UL, range_out.location);
+  EXPECT_EQ(5UL, range_out.length);
+  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(-1, 5), &range_out));
+  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(5, -1), &range_out));
+  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(-1, -1), &range_out));
+  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(LONG_MAX, LONG_MAX), &range_out));
+  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(LONG_MIN, LONG_MAX), &range_out));
+}
+
 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
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index f8ffa97..a452a39 100644
--- a/base/mac/mac_util.h
+++ b/base/mac/mac_util.h
@@ -145,18 +145,24 @@
 
 // Yosemite is Mac OS X 10.10, Darwin 14.
 BASE_EXPORT bool IsOSYosemite();
+BASE_EXPORT bool IsOSYosemiteOrEarlier();
 BASE_EXPORT bool IsOSYosemiteOrLater();
 
+// El Capitan is Mac OS X 10.11, Darwin 15.
+BASE_EXPORT bool IsOSElCapitan();
+BASE_EXPORT bool IsOSElCapitanOrLater();
+
 // 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();
+BASE_EXPORT bool IsOSLaterThanElCapitan_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(); }
+inline bool IsOSYosemiteOrEarlier() { return !IsOSElCapitanOrLater(); }
 
 // 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
@@ -210,7 +216,19 @@
     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
+
+#if defined(MAC_OS_X_VERSION_10_11) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_11
+inline bool IsOSElCapitanOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_11) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_11
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_11
+inline bool IsOSElCapitan() { return false; }
+inline bool IsOSLaterThanElCapitan_DontCallThis() { return true; }
 #endif
 
 // Retrieve the system's model identifier string from the IOKit registry:
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
index bdf45de..647faf3 100644
--- a/base/mac/mac_util.mm
+++ b/base/mac/mac_util.mm
@@ -463,7 +463,7 @@
   // 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 "
+  DLOG_IF(WARNING, darwin_major_version > 15) << "Assuming Darwin "
       << base::IntToString(darwin_major_version) << " is Mac OS X 10."
       << base::IntToString(mac_os_x_minor_version);
 
@@ -483,6 +483,7 @@
   MOUNTAIN_LION_MINOR_VERSION = 8,
   MAVERICKS_MINOR_VERSION = 9,
   YOSEMITE_MINOR_VERSION = 10,
+  EL_CAPITAN_MINOR_VERSION = 11,
 };
 
 }  // namespace
@@ -541,9 +542,21 @@
 }
 #endif
 
-#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_10)
-bool IsOSLaterThanYosemite_DontCallThis() {
-  return MacOSXMinorVersion() > YOSEMITE_MINOR_VERSION;
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_11)
+bool IsOSElCapitan() {
+  return MacOSXMinorVersion() == EL_CAPITAN_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_11)
+bool IsOSElCapitanOrLater() {
+  return MacOSXMinorVersion() >= EL_CAPITAN_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_11)
+bool IsOSLaterThanElCapitan_DontCallThis() {
+  return MacOSXMinorVersion() > EL_CAPITAN_MINOR_VERSION;
 }
 #endif
 
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm
index 3982ab0..35b6e56 100644
--- a/base/mac/mac_util_unittest.mm
+++ b/base/mac/mac_util_unittest.mm
@@ -154,8 +154,11 @@
       EXPECT_TRUE(IsOSMavericksOrEarlier());
       EXPECT_FALSE(IsOSMavericksOrLater());
       EXPECT_FALSE(IsOSYosemite());
+      EXPECT_TRUE(IsOSYosemiteOrEarlier());
       EXPECT_FALSE(IsOSYosemiteOrLater());
-      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+      EXPECT_FALSE(IsOSElCapitan());
+      EXPECT_FALSE(IsOSElCapitanOrLater());
+      EXPECT_FALSE(IsOSLaterThanElCapitan_DontCallThis());
     } else if (minor == 7) {
       EXPECT_FALSE(IsOSSnowLeopard());
       EXPECT_TRUE(IsOSLion());
@@ -168,8 +171,11 @@
       EXPECT_TRUE(IsOSMavericksOrEarlier());
       EXPECT_FALSE(IsOSMavericksOrLater());
       EXPECT_FALSE(IsOSYosemite());
+      EXPECT_TRUE(IsOSYosemiteOrEarlier());
       EXPECT_FALSE(IsOSYosemiteOrLater());
-      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+      EXPECT_FALSE(IsOSElCapitan());
+      EXPECT_FALSE(IsOSElCapitanOrLater());
+      EXPECT_FALSE(IsOSLaterThanElCapitan_DontCallThis());
     } else if (minor == 8) {
       EXPECT_FALSE(IsOSSnowLeopard());
       EXPECT_FALSE(IsOSLion());
@@ -182,8 +188,11 @@
       EXPECT_TRUE(IsOSMavericksOrEarlier());
       EXPECT_FALSE(IsOSMavericksOrLater());
       EXPECT_FALSE(IsOSYosemite());
+      EXPECT_TRUE(IsOSYosemiteOrEarlier());
       EXPECT_FALSE(IsOSYosemiteOrLater());
-      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+      EXPECT_FALSE(IsOSElCapitan());
+      EXPECT_FALSE(IsOSElCapitanOrLater());
+      EXPECT_FALSE(IsOSLaterThanElCapitan_DontCallThis());
     } else if (minor == 9) {
       EXPECT_FALSE(IsOSSnowLeopard());
       EXPECT_FALSE(IsOSLion());
@@ -196,8 +205,11 @@
       EXPECT_TRUE(IsOSMavericksOrEarlier());
       EXPECT_TRUE(IsOSMavericksOrLater());
       EXPECT_FALSE(IsOSYosemite());
+      EXPECT_TRUE(IsOSYosemiteOrEarlier());
       EXPECT_FALSE(IsOSYosemiteOrLater());
-      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+      EXPECT_FALSE(IsOSElCapitan());
+      EXPECT_FALSE(IsOSElCapitanOrLater());
+      EXPECT_FALSE(IsOSLaterThanElCapitan_DontCallThis());
     } else if (minor == 10) {
       EXPECT_FALSE(IsOSSnowLeopard());
       EXPECT_FALSE(IsOSLion());
@@ -210,10 +222,30 @@
       EXPECT_FALSE(IsOSMavericksOrEarlier());
       EXPECT_TRUE(IsOSMavericksOrLater());
       EXPECT_TRUE(IsOSYosemite());
+      EXPECT_TRUE(IsOSYosemiteOrEarlier());
       EXPECT_TRUE(IsOSYosemiteOrLater());
-      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+      EXPECT_FALSE(IsOSElCapitan());
+      EXPECT_FALSE(IsOSElCapitanOrLater());
+      EXPECT_FALSE(IsOSLaterThanElCapitan_DontCallThis());
+    } else if (minor == 11) {
+      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_FALSE(IsOSYosemite());
+      EXPECT_FALSE(IsOSYosemiteOrEarlier());
+      EXPECT_TRUE(IsOSYosemiteOrLater());
+      EXPECT_TRUE(IsOSElCapitan());
+      EXPECT_TRUE(IsOSElCapitanOrLater());
+      EXPECT_FALSE(IsOSLaterThanElCapitan_DontCallThis());
     } else {
-      // Not six, seven, eight, nine, or ten. Ah, ah, ah.
+      // Not six, seven, eight, nine, ten, or eleven. Ah, ah, ah.
       EXPECT_TRUE(false);
     }
   } else {
diff --git a/base/mac/scoped_mach_port.h b/base/mac/scoped_mach_port.h
index beb62b0..67fed6b 100644
--- a/base/mac/scoped_mach_port.h
+++ b/base/mac/scoped_mach_port.h
@@ -45,40 +45,21 @@
 // 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(); }
-};
+using ScopedMachSendRight =
+    ScopedGeneric<mach_port_t, internal::SendRightTraits>;
 
 // A scoper for handling a Mach port's receive right. There is only one
 // receive right per port. This takes ownership of the receive right on
 // construction and then destroys the right on destruction, turning all
 // outstanding send rights into dead names.
-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(); }
-};
+using ScopedMachReceiveRight =
+    ScopedGeneric<mach_port_t, internal::ReceiveRightTraits>;
 
 // A scoper for handling a Mach port set. A port set can have only one
 // reference. This takes ownership of that single reference on construction and
 // destroys the port set on destruction. Destroying a port set does not destroy
 // the receive rights that are members of the port set.
-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(); }
-};
+using ScopedMachPortSet = ScopedGeneric<mach_port_t, internal::PortSetTraits>;
 
 }  // namespace mac
 }  // namespace base
diff --git a/base/mac/scoped_nsexception_enabler.h b/base/mac/scoped_nsexception_enabler.h
deleted file mode 100644
index 484dd53..0000000
--- a/base/mac/scoped_nsexception_enabler.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All 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
deleted file mode 100644
index 7b8ad92..0000000
--- a/base/mac/scoped_nsexception_enabler.mm
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2012 The Chromium 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_sending_event_unittest.mm b/base/mac/scoped_sending_event_unittest.mm
index 02ef2db..52f18c6 100644
--- a/base/mac/scoped_sending_event_unittest.mm
+++ b/base/mac/scoped_sending_event_unittest.mm
@@ -9,7 +9,7 @@
 #include "base/mac/scoped_nsobject.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-@interface ScopedSendingEventTestCrApp : NSObject <CrAppControlProtocol> {
+@interface ScopedSendingEventTestCrApp : NSApplication <CrAppControlProtocol> {
  @private
   BOOL handlingSendEvent_;
 }
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index d70a6aa..44e0b8f 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -176,11 +176,6 @@
                       aborted:(BOOL)aborted;
 @end
 
-@protocol NSWindowDelegateFullScreenAdditions
-- (void)windowDidFailToEnterFullScreen:(NSWindow*)window;
-- (void)windowDidFailToExitFullScreen:(NSWindow*)window;
-@end
-
 enum {
   CBPeripheralStateDisconnected = 0,
   CBPeripheralStateConnecting,
@@ -229,6 +224,26 @@
 
 #endif  // MAC_OS_X_VERSION_10_9
 
+#if !defined(MAC_OS_X_VERSION_10_11) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
+
+enum {
+  NSPressureBehaviorUnknown = -1,
+  NSPressureBehaviorPrimaryDefault = 0,
+  NSPressureBehaviorPrimaryClick = 1,
+  NSPressureBehaviorPrimaryGeneric = 2,
+  NSPressureBehaviorPrimaryAccelerator = 3,
+  NSPressureBehaviorPrimaryDeepClick = 5,
+  NSPressureBehaviorPrimaryDeepDrag = 6
+};
+typedef NSInteger NSPressureBehavior;
+
+@interface NSPressureConfiguration : NSObject
+- (instancetype)initWithPressureBehavior:(NSPressureBehavior)pressureBehavior;
+@end
+
+#endif // MAC_OS_X_VERSION_10_11
+
 // ----------------------------------------------------------------------------
 // Define NSStrings only available in newer versions of the OSX SDK to force
 // them to be statically linked.
@@ -244,6 +259,7 @@
 BASE_EXPORT extern NSString* const
     NSWindowDidChangeBackingPropertiesNotification;
 BASE_EXPORT extern NSString* const CBAdvertisementDataServiceDataKey;
+BASE_EXPORT extern NSString* const CBAdvertisementDataServiceUUIDsKey;
 BASE_EXPORT extern NSString* const
     NSPreferredScrollerStyleDidChangeNotification;
 #endif  // MAC_OS_X_VERSION_10_7
@@ -251,6 +267,7 @@
 #if !defined(MAC_OS_X_VERSION_10_9) || \
     MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
 BASE_EXPORT extern NSString* const NSWindowDidChangeOcclusionStateNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataOverflowServiceUUIDsKey;
 BASE_EXPORT extern NSString* const CBAdvertisementDataIsConnectable;
 #endif  // MAC_OS_X_VERSION_10_9
 
@@ -311,6 +328,7 @@
 - (void)toggleFullScreen:(id)sender;
 - (void)setRestorable:(BOOL)flag;
 - (NSRect)convertRectFromScreen:(NSRect)aRect;
+- (NSSize)convertRectToScreen:(NSRect)aRect;
 @end
 
 @interface NSCursor (LionSDKDeclarations)
@@ -494,6 +512,21 @@
 - (NSString*)UUIDString;
 @end
 
+@interface NSViewController (YosemiteSDK)
+- (void)viewDidLoad;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_10
+
+// Once Chrome no longer supports OSX 10.10.2, everything within this
+// preprocessor block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_10_3) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10_3
+
+@interface NSView (YosemiteSDK)
+- (void)setPressureConfiguration:(NSPressureConfiguration*)aConfiguration;
+@end
+
 #endif  // MAC_OS_X_VERSION_10_10
 
 // ----------------------------------------------------------------------------
diff --git a/base/mac/sdk_forward_declarations.mm b/base/mac/sdk_forward_declarations.mm
index 2e4b2d9..7c5e260 100644
--- a/base/mac/sdk_forward_declarations.mm
+++ b/base/mac/sdk_forward_declarations.mm
@@ -23,6 +23,8 @@
 
 NSString* const CBAdvertisementDataServiceDataKey = @"kCBAdvDataServiceData";
 
+NSString* const CBAdvertisementDataServiceUUIDsKey = @"kCBAdvDataServiceUUIDs";
+
 NSString* const NSPreferredScrollerStyleDidChangeNotification =
     @"NSPreferredScrollerStyleDidChangeNotification";
 #endif  // MAC_OS_X_VERSION_10_7
@@ -32,6 +34,9 @@
 NSString* const NSWindowDidChangeOcclusionStateNotification =
     @"NSWindowDidChangeOcclusionStateNotification";
 
+NSString* const CBAdvertisementDataOverflowServiceUUIDsKey =
+    @"kCBAdvDataOverflowServiceUUIDs";
+
 NSString* const CBAdvertisementDataIsConnectable = @"kCBAdvDataIsConnectable";
 #endif  // MAC_OS_X_VERSION_10_9
 
diff --git a/base/macros.h b/base/macros.h
index d904328..4adbbb0 100644
--- a/base/macros.h
+++ b/base/macros.h
@@ -13,13 +13,13 @@
 #include <stddef.h>  // For size_t.
 #include <string.h>  // For memcpy.
 
-// Put this in the private: declarations for a class to be uncopyable.
+// Put this in the declarations for a class to be uncopyable.
 #define DISALLOW_COPY(TypeName) \
-  TypeName(const TypeName&)
+  TypeName(const TypeName&) = delete
 
-// Put this in the private: declarations for a class to be unassignable.
+// Put this in the declarations for a class to be unassignable.
 #define DISALLOW_ASSIGN(TypeName) \
-  void operator=(const TypeName&)
+  void operator=(const TypeName&) = delete
 
 // A macro to disallow the copy constructor and operator= functions
 // This should be used in the private: declarations for a class
@@ -41,7 +41,7 @@
 // that wants to prevent anyone from instantiating it. This is
 // especially useful for classes containing only static methods.
 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-  TypeName();                                    \
+  TypeName() = delete;                           \
   DISALLOW_COPY_AND_ASSIGN(TypeName)
 
 // The arraysize(arr) macro returns the # of elements in an array arr.
@@ -55,47 +55,6 @@
 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
@@ -152,7 +111,8 @@
 
 template <class Dest, class Source>
 inline Dest bit_cast(const Source& source) {
-  COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), VerifySizesAreEqual);
+  static_assert(sizeof(Dest) == sizeof(Source),
+                "bit_cast requires source and destination to be the same size");
 
   Dest dest;
   memcpy(&dest, &source, sizeof(dest));
diff --git a/base/memory/BUILD.gn b/base/memory/BUILD.gn
index bd864ca..2070447 100644
--- a/base/memory/BUILD.gn
+++ b/base/memory/BUILD.gn
@@ -18,6 +18,12 @@
     "memory_pressure_listener.h",
     "memory_pressure_monitor.cc",
     "memory_pressure_monitor.h",
+    "memory_pressure_monitor_chromeos.cc",
+    "memory_pressure_monitor_chromeos.h",
+    "memory_pressure_monitor_mac.cc",
+    "memory_pressure_monitor_mac.h",
+    "memory_pressure_monitor_win.cc",
+    "memory_pressure_monitor_win.h",
     "raw_scoped_refptr_mismatch_checker.h",
     "ref_counted.cc",
     "ref_counted.h",
@@ -29,6 +35,10 @@
     "scoped_vector.h",
     "shared_memory.h",
     "shared_memory_android.cc",
+    "shared_memory_handle.h",
+    "shared_memory_handle_mac.cc",
+    "shared_memory_handle_win.cc",
+    "shared_memory_mac.cc",
     "shared_memory_nacl.cc",
     "shared_memory_posix.cc",
     "shared_memory_win.cc",
@@ -37,6 +47,12 @@
     "weak_ptr.cc",
     "weak_ptr.h",
   ]
+  if (is_ios) {
+    sources -= [
+      "discardable_shared_memory.cc",
+      "discardable_shared_memory.h",
+    ]
+  }
 
   if (is_nacl) {
     sources -= [
@@ -52,6 +68,16 @@
     sources -= [ "shared_memory_nacl.cc" ]
   }
 
+  if (is_mac) {
+    sources -= [ "shared_memory_posix.cc" ]
+  }
+
+  if (is_android) {
+    deps = [
+      "//third_party/ashmem",
+    ]
+  }
+
   configs += [ "//base:base_implementation" ]
 
   visibility = [ "//base/*" ]
diff --git a/base/memory/OWNERS b/base/memory/OWNERS
new file mode 100644
index 0000000..bcaf778
--- /dev/null
+++ b/base/memory/OWNERS
@@ -0,0 +1,2 @@
+per-file *chromeos*=skuhne@chromium.org
+per-file *chromeos*=oshima@chromium.org
diff --git a/base/memory/discardable_memory.h b/base/memory/discardable_memory.h
index fc189e7..c64fc4f 100644
--- a/base/memory/discardable_memory.h
+++ b/base/memory/discardable_memory.h
@@ -11,6 +11,11 @@
 
 namespace base {
 
+namespace trace_event {
+class MemoryAllocatorDump;
+class ProcessMemoryDump;
+}
+
 // 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
@@ -59,6 +64,14 @@
   template<typename T> T* data_as() const {
     return reinterpret_cast<T*>(data());
   }
+
+  // Used for dumping the statistics of discardable memory allocated in tracing.
+  // Returns a new MemoryAllocatorDump in the |pmd| with the size of the
+  // discardable memory. The MemoryAllocatorDump created is owned by |pmd|. See
+  // ProcessMemoryDump::CreateAllocatorDump.
+  virtual trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump(
+      const char* name,
+      trace_event::ProcessMemoryDump* pmd) const = 0;
 };
 
 }  // namespace base
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc
index 830d6b9..2b0cfd0 100644
--- a/base/memory/discardable_shared_memory.cc
+++ b/base/memory/discardable_shared_memory.cc
@@ -4,13 +4,15 @@
 
 #include "base/memory/discardable_shared_memory.h"
 
-#if defined(OS_POSIX)
-#include <unistd.h>
+#if defined(OS_POSIX) && !defined(OS_NACL)
+// For madvise() which is available on all POSIX compatible systems.
+#include <sys/mman.h>
 #endif
 
 #include <algorithm>
 
 #include "base/atomicops.h"
+#include "base/bits.h"
 #include "base/logging.h"
 #include "base/numerics/safe_math.h"
 #include "base/process/process_metrics.h"
@@ -19,6 +21,10 @@
 #include "third_party/ashmem/ashmem.h"
 #endif
 
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 namespace base {
 namespace {
 
@@ -89,15 +95,9 @@
   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);
+  return bits::Align(size, base::GetPageSize());
 }
 
 }  // namespace
@@ -122,8 +122,15 @@
   if (!checked_size.IsValid())
     return false;
 
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // DiscardableSharedMemory does not yet support a Mach-implementation, so
+  // force the underlying primitive to be a POSIX fd. https://crbug.com/547239.
+  if (!shared_memory_.CreateAndMapAnonymousPosix(checked_size.ValueOrDie()))
+    return false;
+#else
   if (!shared_memory_.CreateAndMapAnonymous(checked_size.ValueOrDie()))
     return false;
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 
   mapped_size_ =
       shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
@@ -157,6 +164,14 @@
   return true;
 }
 
+bool DiscardableSharedMemory::Unmap() {
+  if (!shared_memory_.Unmap())
+    return false;
+
+  mapped_size_ = 0;
+  return true;
+}
+
 DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
     size_t offset, size_t length) {
   DCHECK_EQ(AlignToPageSize(offset), offset);
@@ -210,12 +225,22 @@
   DCHECK_EQ(locked_pages_.size(), locked_page_count_);
 #endif
 
+// Pin pages if supported.
 #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;
+  if (SharedMemory::IsHandleValid(handle)) {
+    if (ashmem_pin_region(
+            handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+      return PURGED;
+    }
+  }
+#elif defined(OS_WIN)
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+    if (!VirtualAlloc(reinterpret_cast<char*>(shared_memory_.memory()) +
+                          AlignToPageSize(sizeof(SharedState)) + offset,
+                      length, MEM_RESET_UNDO, PAGE_READWRITE)) {
+      return PURGED;
+    }
   }
 #endif
 
@@ -235,12 +260,26 @@
 
   DCHECK(shared_memory_.memory());
 
+// Unpin pages if supported.
 #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";
+  if (SharedMemory::IsHandleValid(handle)) {
+    if (ashmem_unpin_region(
+            handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+      DPLOG(ERROR) << "ashmem_unpin_region() failed";
+    }
+  }
+#elif defined(OS_WIN)
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+    // Note: MEM_RESET is not technically gated on Win8.  However, this Unlock
+    // function needs to match the Lock behaviour (MEM_RESET_UNDO) to properly
+    // implement memory pinning.  It needs to bias towards preserving the
+    // contents of memory between an Unlock and next Lock.
+    if (!VirtualAlloc(reinterpret_cast<char*>(shared_memory_.memory()) +
+                          AlignToPageSize(sizeof(SharedState)) + offset,
+                      length, MEM_RESET, PAGE_READWRITE)) {
+      DPLOG(ERROR) << "VirtualAlloc() MEM_RESET failed in Unlock()";
+    }
   }
 #endif
 
@@ -296,11 +335,7 @@
 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;
+  DCHECK(shared_memory_.memory());
 
   SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
   SharedState new_state(SharedState::UNLOCKED, Time());
@@ -321,6 +356,39 @@
     return false;
   }
 
+// The next section will release as much resource as can be done
+// from the purging process, until the client process notices the
+// purge and releases its own references.
+// Note: this memory will not be accessed again.  The segment will be
+// freed asynchronously at a later time, so just do the best
+// immediately.
+#if defined(OS_POSIX) && !defined(OS_NACL)
+// Linux and Android provide MADV_REMOVE which is preferred as it has a
+// behavior that can be verified in tests. Other POSIX flavors (MacOSX, BSDs),
+// provide MADV_FREE which has the same result but memory is purged lazily.
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#define MADV_PURGE_ARGUMENT MADV_REMOVE
+#else
+#define MADV_PURGE_ARGUMENT MADV_FREE
+#endif
+  // Advise the kernel to remove resources associated with purged pages.
+  // Subsequent accesses of memory pages will succeed, but might result in
+  // zero-fill-on-demand pages.
+  if (madvise(reinterpret_cast<char*>(shared_memory_.memory()) +
+                  AlignToPageSize(sizeof(SharedState)),
+              AlignToPageSize(mapped_size_), MADV_PURGE_ARGUMENT)) {
+    DPLOG(ERROR) << "madvise() failed";
+  }
+#elif defined(OS_WIN)
+  // MEM_DECOMMIT the purged pages to release the physical storage,
+  // either in memory or in the paging file on disk.  Pages remain RESERVED.
+  if (!VirtualFree(reinterpret_cast<char*>(shared_memory_.memory()) +
+                       AlignToPageSize(sizeof(SharedState)),
+                   AlignToPageSize(mapped_size_), MEM_DECOMMIT)) {
+    DPLOG(ERROR) << "VirtualFree() MEM_DECOMMIT failed in Purge()";
+  }
+#endif
+
   last_known_usage_ = Time();
   return true;
 }
@@ -335,32 +403,19 @@
          !result.GetTimestamp().is_null();
 }
 
+bool DiscardableSharedMemory::IsMemoryLocked() const {
+  DCHECK(shared_memory_.memory());
+
+  SharedState result(subtle::NoBarrier_Load(
+      &SharedStateFromSharedMemory(shared_memory_)->value.i));
+
+  return result.GetLockState() == SharedState::LOCKED;
+}
+
 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();
 }
diff --git a/base/memory/discardable_shared_memory.h b/base/memory/discardable_shared_memory.h
index 892d556..0b5ac9f 100644
--- a/base/memory/discardable_shared_memory.h
+++ b/base/memory/discardable_shared_memory.h
@@ -15,10 +15,15 @@
 #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
+// Linux (including Android) support the MADV_REMOVE argument with madvise()
+// which has the behavior of reliably causing zero-fill-on-demand pages to
+// be returned after a call. Here we define
+// DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE on Linux
+// and Android to indicate that this type of behavior can be expected on
+// those platforms. Note that madvise() will still be used on other POSIX
+// platforms but doesn't provide the zero-fill-on-demand pages guarantee.
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#define DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE
 #endif
 
 namespace base {
@@ -48,6 +53,11 @@
   // Returns true on success, false otherwise.
   bool Map(size_t size);
 
+  // Unmaps the discardable shared memory from the caller's address space.
+  // Returns true if successful; returns false on error or if the memory is
+  // not mapped.
+  bool Unmap();
+
   // The actual size of the mapped memory (may be larger than requested).
   size_t mapped_size() const { return mapped_size_; }
 
@@ -102,6 +112,9 @@
   // Returns true if memory is still resident.
   bool IsMemoryResident() const;
 
+  // Returns true if memory is locked.
+  bool IsMemoryLocked() const;
+
   // Closes the open discardable memory segment.
   // It is safe to call Close repeatedly.
   void Close();
@@ -116,12 +129,6 @@
     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;
diff --git a/base/memory/discardable_shared_memory_unittest.cc b/base/memory/discardable_shared_memory_unittest.cc
index ae7235d..aaa6c0d 100644
--- a/base/memory/discardable_shared_memory_unittest.cc
+++ b/base/memory/discardable_shared_memory_unittest.cc
@@ -33,6 +33,7 @@
   bool rv = memory.CreateAndMap(kDataSize);
   ASSERT_TRUE(rv);
   EXPECT_GE(memory.mapped_size(), kDataSize);
+  EXPECT_TRUE(memory.IsMemoryLocked());
 }
 
 TEST(DiscardableSharedMemoryTest, CreateFromHandle) {
@@ -50,6 +51,7 @@
   TestDiscardableSharedMemory memory2(shared_handle);
   rv = memory2.Map(kDataSize);
   ASSERT_TRUE(rv);
+  EXPECT_TRUE(memory2.IsMemoryLocked());
 }
 
 TEST(DiscardableSharedMemoryTest, LockAndUnlock) {
@@ -62,6 +64,7 @@
   // Memory is initially locked. Unlock it.
   memory1.SetNow(Time::FromDoubleT(1));
   memory1.Unlock(0, 0);
+  EXPECT_FALSE(memory1.IsMemoryLocked());
 
   // Lock and unlock memory.
   auto lock_rv = memory1.Lock(0, 0);
@@ -72,6 +75,7 @@
   // Lock again before duplicating and passing ownership to new instance.
   lock_rv = memory1.Lock(0, 0);
   EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+  EXPECT_TRUE(memory1.IsMemoryLocked());
 
   SharedMemoryHandle shared_handle;
   ASSERT_TRUE(
@@ -86,13 +90,18 @@
   memory2.SetNow(Time::FromDoubleT(3));
   memory2.Unlock(0, 0);
 
+  // Both memory instances should be unlocked now.
+  EXPECT_FALSE(memory2.IsMemoryLocked());
+  EXPECT_FALSE(memory1.IsMemoryLocked());
+
   // 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.
+  // Memory should still be resident and locked.
   rv = memory1.IsMemoryResident();
   EXPECT_TRUE(rv);
+  EXPECT_TRUE(memory1.IsMemoryLocked());
 
   // Unlock first instance.
   memory1.SetNow(Time::FromDoubleT(4));
@@ -306,24 +315,72 @@
 
   EXPECT_LE(kDataSize, memory.mapped_size());
 
-  // Mapped size should be 0 after memory segment has been closed.
-  memory.Close();
+  // Mapped size should be 0 after memory segment has been unmapped.
+  rv = memory.Unmap();
+  EXPECT_TRUE(rv);
   EXPECT_EQ(0u, memory.mapped_size());
 }
 
-#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
-TEST(DiscardableSharedMemoryTest, Shrink) {
+TEST(DiscardableSharedMemoryTest, Close) {
   const uint32 kDataSize = 1024;
 
   TestDiscardableSharedMemory memory;
   bool rv = memory.CreateAndMap(kDataSize);
   ASSERT_TRUE(rv);
 
-  EXPECT_NE(0u, memory.mapped_size());
+  // Mapped size should be unchanged after memory segment has been closed.
+  memory.Close();
+  EXPECT_LE(kDataSize, memory.mapped_size());
 
-  // Mapped size should be 0 after shrinking memory segment.
-  memory.Shrink();
-  EXPECT_EQ(0u, memory.mapped_size());
+  // Memory is initially locked. Unlock it.
+  memory.SetNow(Time::FromDoubleT(1));
+  memory.Unlock(0, 0);
+
+  // Lock and unlock memory.
+  auto lock_rv = memory.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+  memory.SetNow(Time::FromDoubleT(2));
+  memory.Unlock(0, 0);
+}
+
+// This test checks that zero-filled pages are returned after purging a segment
+// when DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE is
+// defined and MADV_REMOVE is supported.
+#if defined(DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE)
+TEST(DiscardableSharedMemoryTest, ZeroFilledPagesAfterPurge) {
+  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);
+
+  // Initialize all memory to '0xaa'.
+  memset(memory2.memory(), 0xaa, kDataSize);
+
+  // Unlock memory.
+  memory2.SetNow(Time::FromDoubleT(1));
+  memory2.Unlock(0, 0);
+  EXPECT_FALSE(memory1.IsMemoryLocked());
+
+  // Memory is unlocked, but our usage timestamp is incorrect.
+  rv = memory1.Purge(Time::FromDoubleT(2));
+  EXPECT_FALSE(rv);
+  rv = memory1.Purge(Time::FromDoubleT(3));
+  EXPECT_TRUE(rv);
+
+  // Check that reading memory after it has been purged is returning
+  // zero-filled pages.
+  uint8 expected_data[kDataSize] = {};
+  EXPECT_EQ(memcmp(memory2.memory(), expected_data, kDataSize), 0);
 }
 #endif
 
diff --git a/base/memory/linked_ptr.h b/base/memory/linked_ptr.h
index 80044ad..649dc10 100644
--- a/base/memory/linked_ptr.h
+++ b/base/memory/linked_ptr.h
@@ -17,10 +17,6 @@
 //   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!).
@@ -73,6 +69,8 @@
   mutable linked_ptr_internal const* next_;
 };
 
+// TODO(http://crbug.com/556939): DEPRECATED: Use scoped_ptr instead (now that
+// we have support for moveable types inside STL containers).
 template <typename T>
 class linked_ptr {
  public:
diff --git a/base/memory/memory_pressure_listener.cc b/base/memory/memory_pressure_listener.cc
index 6a8ed21..9fd675a 100644
--- a/base/memory/memory_pressure_listener.cc
+++ b/base/memory/memory_pressure_listener.cc
@@ -8,31 +8,35 @@
 #include "base/observer_list_threadsafe.h"
 #include "base/trace_event/trace_event.h"
 
+namespace base {
+
 namespace {
 
 // ObserverListThreadSafe is RefCountedThreadSafe, this traits is needed
 // to ensure the LazyInstance will hold a reference to it.
 struct LeakyLazyObserverListTraits :
     base::internal::LeakyLazyInstanceTraits<
-        ObserverListThreadSafe<base::MemoryPressureListener> > {
-  static ObserverListThreadSafe<base::MemoryPressureListener>*
+        ObserverListThreadSafe<MemoryPressureListener> > {
+  static ObserverListThreadSafe<MemoryPressureListener>*
       New(void* instance) {
-    ObserverListThreadSafe<base::MemoryPressureListener>* ret =
+    ObserverListThreadSafe<MemoryPressureListener>* ret =
         base::internal::LeakyLazyInstanceTraits<
-            ObserverListThreadSafe<base::MemoryPressureListener> >::New(
-                instance);
+            ObserverListThreadSafe<MemoryPressureListener>>::New(instance);
     // Leaky.
     ret->AddRef();
     return ret;
   }
 };
 
-base::LazyInstance<
-    ObserverListThreadSafe<base::MemoryPressureListener>,
+LazyInstance<
+    ObserverListThreadSafe<MemoryPressureListener>,
     LeakyLazyObserverListTraits> g_observers = LAZY_INSTANCE_INITIALIZER;
-}  // namespace
 
-namespace base {
+// All memory pressure notifications within this process will be suppressed if
+// this variable is set to 1.
+subtle::Atomic32 g_notifications_suppressed = 0;
+
+}  // namespace
 
 MemoryPressureListener::MemoryPressureListener(
     const MemoryPressureListener::MemoryPressureCallback& callback)
@@ -54,6 +58,32 @@
   DCHECK_NE(memory_pressure_level, MEMORY_PRESSURE_LEVEL_NONE);
   TRACE_EVENT1("memory", "MemoryPressureListener::NotifyMemoryPressure",
       "level", memory_pressure_level);
+  if (AreNotificationsSuppressed())
+    return;
+  DoNotifyMemoryPressure(memory_pressure_level);
+}
+
+// static
+bool MemoryPressureListener::AreNotificationsSuppressed() {
+  return subtle::Acquire_Load(&g_notifications_suppressed) == 1;
+}
+
+// static
+void MemoryPressureListener::SetNotificationsSuppressed(bool suppress) {
+  subtle::Release_Store(&g_notifications_suppressed, suppress ? 1 : 0);
+}
+
+// static
+void MemoryPressureListener::SimulatePressureNotification(
+    MemoryPressureLevel memory_pressure_level) {
+  // Notify all listeners even if regular pressure notifications are suppressed.
+  DoNotifyMemoryPressure(memory_pressure_level);
+}
+
+// static
+void MemoryPressureListener::DoNotifyMemoryPressure(
+    MemoryPressureLevel memory_pressure_level) {
+  DCHECK_NE(memory_pressure_level, MEMORY_PRESSURE_LEVEL_NONE);
   g_observers.Get().Notify(FROM_HERE, &MemoryPressureListener::Notify,
                            memory_pressure_level);
 }
diff --git a/base/memory/memory_pressure_listener.h b/base/memory/memory_pressure_listener.h
index 6adaeee..290657e 100644
--- a/base/memory/memory_pressure_listener.h
+++ b/base/memory/memory_pressure_listener.h
@@ -72,9 +72,19 @@
   // Intended for use by the platform specific implementation.
   static void NotifyMemoryPressure(MemoryPressureLevel memory_pressure_level);
 
+  // These methods should not be used anywhere else but in memory measurement
+  // code, where they are intended to maintain stable conditions across
+  // measurements.
+  static bool AreNotificationsSuppressed();
+  static void SetNotificationsSuppressed(bool suppressed);
+  static void SimulatePressureNotification(
+      MemoryPressureLevel memory_pressure_level);
+
  private:
   void Notify(MemoryPressureLevel memory_pressure_level);
 
+  static void DoNotifyMemoryPressure(MemoryPressureLevel memory_pressure_level);
+
   MemoryPressureCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryPressureListener);
diff --git a/base/memory/memory_pressure_listener_unittest.cc b/base/memory/memory_pressure_listener_unittest.cc
new file mode 100644
index 0000000..38d429d
--- /dev/null
+++ b/base/memory/memory_pressure_listener_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/memory_pressure_listener.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+
+using MemoryPressureLevel = MemoryPressureListener::MemoryPressureLevel;
+
+class MemoryPressureListenerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    message_loop_.reset(new MessageLoopForUI());
+    listener_.reset(new MemoryPressureListener(
+        Bind(&MemoryPressureListenerTest::OnMemoryPressure, Unretained(this))));
+  }
+
+  void TearDown() override {
+    listener_.reset();
+    message_loop_.reset();
+  }
+
+ protected:
+  void ExpectNotification(
+      void (*notification_function)(MemoryPressureLevel),
+      MemoryPressureLevel level) {
+    EXPECT_CALL(*this, OnMemoryPressure(level)).Times(1);
+    notification_function(level);
+    message_loop_->RunUntilIdle();
+  }
+
+  void ExpectNoNotification(
+      void (*notification_function)(MemoryPressureLevel),
+      MemoryPressureLevel level) {
+    EXPECT_CALL(*this, OnMemoryPressure(testing::_)).Times(0);
+    notification_function(level);
+    message_loop_->RunUntilIdle();
+  }
+
+ private:
+  MOCK_METHOD1(OnMemoryPressure,
+               void(MemoryPressureListener::MemoryPressureLevel));
+
+  scoped_ptr<MessageLoopForUI> message_loop_;
+  scoped_ptr<MemoryPressureListener> listener_;
+};
+
+TEST_F(MemoryPressureListenerTest, NotifyMemoryPressure) {
+  // Memory pressure notifications are not suppressed by default.
+  EXPECT_FALSE(MemoryPressureListener::AreNotificationsSuppressed());
+  ExpectNotification(&MemoryPressureListener::NotifyMemoryPressure,
+                     MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE);
+  ExpectNotification(&MemoryPressureListener::SimulatePressureNotification,
+                     MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE);
+
+  // Enable suppressing memory pressure notifications.
+  MemoryPressureListener::SetNotificationsSuppressed(true);
+  EXPECT_TRUE(MemoryPressureListener::AreNotificationsSuppressed());
+  ExpectNoNotification(&MemoryPressureListener::NotifyMemoryPressure,
+                       MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE);
+  ExpectNotification(&MemoryPressureListener::SimulatePressureNotification,
+                     MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE);
+
+  // Disable suppressing memory pressure notifications.
+  MemoryPressureListener::SetNotificationsSuppressed(false);
+  EXPECT_FALSE(MemoryPressureListener::AreNotificationsSuppressed());
+  ExpectNotification(&MemoryPressureListener::NotifyMemoryPressure,
+                     MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL);
+  ExpectNotification(&MemoryPressureListener::SimulatePressureNotification,
+                     MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL);
+}
+
+}  // namespace base
diff --git a/base/chromeos/memory_pressure_monitor.cc b/base/memory/memory_pressure_monitor_chromeos.cc
similarity index 97%
rename from base/chromeos/memory_pressure_monitor.cc
rename to base/memory/memory_pressure_monitor_chromeos.cc
index 5e8aadf..0c3d979 100644
--- a/base/chromeos/memory_pressure_monitor.cc
+++ b/base/memory/memory_pressure_monitor_chromeos.cc
@@ -2,7 +2,7 @@
 // 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.h"
+#include "base/memory/memory_pressure_monitor_chromeos.h"
 
 #include <fcntl.h>
 #include <sys/select.h>
@@ -11,6 +11,7 @@
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/process_metrics.h"
 #include "base/single_thread_task_runner.h"
+#include "base/sys_info.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 
@@ -114,7 +115,9 @@
       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";
+  LOG_IF(ERROR,
+         base::SysInfo::IsRunningOnChromeOS() && !low_mem_file_.is_valid())
+      << "Cannot open kernel listener";
 }
 
 MemoryPressureMonitor::~MemoryPressureMonitor() {
diff --git a/base/chromeos/memory_pressure_monitor.h b/base/memory/memory_pressure_monitor_chromeos.h
similarity index 93%
rename from base/chromeos/memory_pressure_monitor.h
rename to base/memory/memory_pressure_monitor_chromeos.h
index bed1ec3..5529c3b 100644
--- a/base/chromeos/memory_pressure_monitor.h
+++ b/base/memory/memory_pressure_monitor_chromeos.h
@@ -2,12 +2,11 @@
 // 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_H_
-#define BASE_CHROMEOS_MEMORY_PRESSURE_MONITOR_H_
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_MONITOR_CHROMEOS_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_CHROMEOS_H_
 
 #include "base/base_export.h"
 #include "base/files/scoped_file.h"
-#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/memory_pressure_listener.h"
 #include "base/memory/memory_pressure_monitor.h"
@@ -95,7 +94,7 @@
 
   // A periodic timer to check for resource pressure changes. This will get
   // replaced by a kernel triggered event system (see crbug.com/381196).
-  base::RepeatingTimer<MemoryPressureMonitor> timer_;
+  base::RepeatingTimer 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.
@@ -116,4 +115,4 @@
 }  // namespace chromeos
 }  // namespace base
 
-#endif  // BASE_CHROMEOS_MEMORY_PRESSURE_MONITOR_H_
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_CHROMEOS_H_
diff --git a/base/chromeos/memory_pressure_monitor_unittest.cc b/base/memory/memory_pressure_monitor_chromeos_unittest.cc
similarity index 98%
rename from base/chromeos/memory_pressure_monitor_unittest.cc
rename to base/memory/memory_pressure_monitor_chromeos_unittest.cc
index 4fb8332..e0afa44 100644
--- a/base/chromeos/memory_pressure_monitor_unittest.cc
+++ b/base/memory/memory_pressure_monitor_chromeos_unittest.cc
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/memory_pressure_monitor_chromeos.h"
+
 #include "base/basictypes.h"
-#include "base/chromeos/memory_pressure_monitor.h"
 #include "base/memory/memory_pressure_listener.h"
 #include "base/message_loop/message_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/mac/memory_pressure_monitor.cc b/base/memory/memory_pressure_monitor_mac.cc
similarity index 97%
rename from base/mac/memory_pressure_monitor.cc
rename to base/memory/memory_pressure_monitor_mac.cc
index 5667aa6..f394935 100644
--- a/base/mac/memory_pressure_monitor.cc
+++ b/base/memory/memory_pressure_monitor_mac.cc
@@ -2,7 +2,7 @@
 // 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.h"
+#include "base/memory/memory_pressure_monitor_mac.h"
 
 #include <dlfcn.h>
 #include <sys/sysctl.h>
diff --git a/base/mac/memory_pressure_monitor.h b/base/memory/memory_pressure_monitor_mac.h
similarity index 90%
rename from base/mac/memory_pressure_monitor.h
rename to base/memory/memory_pressure_monitor_mac.h
index afaec27..8d4c26a 100644
--- a/base/mac/memory_pressure_monitor.h
+++ b/base/memory/memory_pressure_monitor_mac.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef BASE_MAC_MEMORY_PRESSURE_MONITOR_H_
-#define BASE_MAC_MEMORY_PRESSURE_MONITOR_H_
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
 
 #include <dispatch/dispatch.h>
 
@@ -60,4 +60,4 @@
 }  // namespace mac
 }  // namespace base
 
-#endif  // BASE_MAC_MEMORY_PRESSURE_MONITOR_H_
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
diff --git a/base/mac/memory_pressure_monitor_unittest.cc b/base/memory/memory_pressure_monitor_mac_unittest.cc
similarity index 97%
rename from base/mac/memory_pressure_monitor_unittest.cc
rename to base/memory/memory_pressure_monitor_mac_unittest.cc
index acb3666..e037a9d 100644
--- a/base/mac/memory_pressure_monitor_unittest.cc
+++ b/base/memory/memory_pressure_monitor_mac_unittest.cc
@@ -2,7 +2,8 @@
 // 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.h"
+#include "base/memory/memory_pressure_monitor_mac.h"
+
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
diff --git a/base/win/memory_pressure_monitor.cc b/base/memory/memory_pressure_monitor_win.cc
similarity index 98%
rename from base/win/memory_pressure_monitor.cc
rename to base/memory/memory_pressure_monitor_win.cc
index ed49a40..4349d03 100644
--- a/base/win/memory_pressure_monitor.cc
+++ b/base/memory/memory_pressure_monitor_win.cc
@@ -2,7 +2,7 @@
 // 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/memory/memory_pressure_monitor_win.h"
 
 #include <windows.h>
 
diff --git a/base/win/memory_pressure_monitor.h b/base/memory/memory_pressure_monitor_win.h
similarity index 96%
rename from base/win/memory_pressure_monitor.h
rename to base/memory/memory_pressure_monitor_win.h
index 933d912..030b8b3 100644
--- a/base/win/memory_pressure_monitor.h
+++ b/base/memory/memory_pressure_monitor_win.h
@@ -2,8 +2,8 @@
 // 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_
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_MONITOR_WIN_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_WIN_H_
 
 #include "base/base_export.h"
 #include "base/memory/memory_pressure_listener.h"
@@ -117,7 +117,7 @@
   int critical_threshold_mb_;
 
   // A periodic timer to check for memory pressure changes.
-  base::RepeatingTimer<MemoryPressureMonitor> timer_;
+  base::RepeatingTimer timer_;
 
   // The current memory pressure.
   MemoryPressureLevel current_memory_pressure_level_;
@@ -141,4 +141,4 @@
 }  // namespace win
 }  // namespace base
 
-#endif  // BASE_WIN_MEMORY_PRESSURE_MONITOR_H_
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_WIN_H_
diff --git a/base/win/memory_pressure_monitor_unittest.cc b/base/memory/memory_pressure_monitor_win_unittest.cc
similarity index 98%
rename from base/win/memory_pressure_monitor_unittest.cc
rename to base/memory/memory_pressure_monitor_win_unittest.cc
index 40a25a7..d9a9575 100644
--- a/base/win/memory_pressure_monitor_unittest.cc
+++ b/base/memory/memory_pressure_monitor_win_unittest.cc
@@ -2,7 +2,7 @@
 // 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/memory/memory_pressure_monitor_win.h"
 
 #include "base/basictypes.h"
 #include "base/memory/memory_pressure_listener.h"
diff --git a/base/memory/raw_scoped_refptr_mismatch_checker.h b/base/memory/raw_scoped_refptr_mismatch_checker.h
index 0190558..09f982b 100644
--- a/base/memory/raw_scoped_refptr_mismatch_checker.h
+++ b/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -51,75 +51,10 @@
   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) };
+template <typename Head, typename... Tail>
+struct ParamsUseScopedRefptrCorrectly<Tuple<Head, Tail...>> {
+  enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
+                 ParamsUseScopedRefptrCorrectly<Tuple<Tail...>>::value };
 };
 
 }  // namespace internal
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
index 5f94b4c..26c6551 100644
--- a/base/memory/ref_counted.h
+++ b/base/memory/ref_counted.h
@@ -331,13 +331,13 @@
   }
 
   scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
-    scoped_refptr<T>(r.Pass()).swap(*this);
+    scoped_refptr<T>(std::move(r)).swap(*this);
     return *this;
   }
 
   template <typename U>
   scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
-    scoped_refptr<T>(r.Pass()).swap(*this);
+    scoped_refptr<T>(std::move(r)).swap(*this);
     return *this;
   }
 
diff --git a/base/memory/ref_counted_delete_on_message_loop.h b/base/memory/ref_counted_delete_on_message_loop.h
index 6a109e8..d278a44 100644
--- a/base/memory/ref_counted_delete_on_message_loop.h
+++ b/base/memory/ref_counted_delete_on_message_loop.h
@@ -8,8 +8,6 @@
 #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 {
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc
index 6f8e599..dbc6f33 100644
--- a/base/memory/ref_counted_unittest.cc
+++ b/base/memory/ref_counted_unittest.cc
@@ -180,26 +180,6 @@
   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();
 
@@ -212,7 +192,7 @@
     {
       scoped_refptr<ScopedRefPtrCountBase> p2;
 
-      p2 = p1.Pass();
+      p2 = std::move(p1);
       EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
       EXPECT_EQ(nullptr, p1.get());
@@ -243,7 +223,7 @@
       EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
 
-      p1 = p2.Pass();
+      p1 = std::move(p2);
       EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
       EXPECT_EQ(raw, p1.get());
@@ -274,7 +254,7 @@
       EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
 
-      p1 = p2.Pass();
+      p1 = std::move(p2);
       EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
       EXPECT_EQ(raw, p1.get());
@@ -305,7 +285,7 @@
       EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
 
-      p2 = p1.Pass();
+      p2 = std::move(p1);
       EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
       EXPECT_EQ(nullptr, p1.get());
@@ -337,7 +317,7 @@
       EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
 
-      p1 = p2.Pass();
+      p1 = std::move(p2);
       EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
       EXPECT_EQ(raw2, p1.get());
@@ -374,7 +354,7 @@
       EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
 
-      p1 = p2.Pass();
+      p1 = std::move(p2);
       EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
       EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
@@ -407,7 +387,7 @@
     EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
 
     {
-      scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+      scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
       EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
       EXPECT_EQ(nullptr, p1.get());
@@ -437,7 +417,7 @@
     EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
 
     {
-      scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+      scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
       EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
       EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
       EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
diff --git a/base/memory/scoped_ptr.h b/base/memory/scoped_ptr.h
index 987ccfa..0120f89 100644
--- a/base/memory/scoped_ptr.h
+++ b/base/memory/scoped_ptr.h
@@ -37,42 +37,43 @@
 // 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:
+// as the argument type, it must be called with an rvalue of a scoper, which
+// can be created by using std::move(), or the result of 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
+//     // Do something with arg.
 //   }
 //   scoped_ptr<Foo> CreateFoo() {
-//     // No need for calling Pass() because we are constructing a temporary
-//     // for the return value.
+//     // No need for calling std::move() for returning a move-only value, or
+//     // when you already have an rvalue as we do here.
 //     return scoped_ptr<Foo>(new Foo("new"));
 //   }
 //   scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
-//     return arg.Pass();
+//     return arg;
 //   }
 //
 //   {
 //     scoped_ptr<Foo> ptr(new Foo("yay"));  // ptr manages Foo("yay").
-//     TakesOwnership(ptr.Pass());           // ptr no longer owns Foo("yay").
+//     TakesOwnership(std::move(ptr));       // 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.
+//         PassThru(std::move(ptr2));        // ptr2 is correspondingly nullptr.
 //   }
 //
-// Notice that if you do not call Pass() when returning from PassThru(), or
+// Notice that if you do not call std::move() 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().
+// the std::move() 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 std::move().
 //
-// Pass() properly handles upcast in initialization, i.e. you can use a
-// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
+// The conversion move-constructor 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());
+//   scoped_ptr<FooParent> parent(std::move(foo));
 
 #ifndef BASE_MEMORY_SCOPED_PTR_H_
 #define BASE_MEMORY_SCOPED_PTR_H_
@@ -84,8 +85,10 @@
 #include <stddef.h>
 #include <stdlib.h>
 
-#include <algorithm>  // For std::swap().
 #include <iosfwd>
+#include <memory>
+#include <type_traits>
+#include <utility>
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
@@ -99,61 +102,6 @@
 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:
 //
@@ -175,17 +123,6 @@
   };
 };
 
-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>
@@ -216,37 +153,28 @@
   }
 
   ~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);
-    }
+    // Match libc++, which calls reset() in its destructor.
+    // Use nullptr as the new value for three reasons:
+    // 1. libc++ does it.
+    // 2. Avoids infinitely recursing into destructors if two classes are owned
+    //    in a reference cycle (see ScopedPtrTest.ReferenceCycle).
+    // 3. If |this| is accessed in the future, in a use-after-free bug, attempts
+    //    to dereference |this|'s pointer should cause either a failure or a
+    //    segfault closer to the problem. If |this| wasn't reset to nullptr,
+    //    the access would cause the deleted memory to be read or written
+    //    leading to other more subtle issues.
+    reset(nullptr);
   }
 
   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.
+    // Match C++11's definition of unique_ptr::reset(), which requires changing
+    // the pointer before invoking the deleter on the old pointer. This prevents
+    // |this| from being accessed after the deleter is run, which may destroy
+    // |this|.
     T* old = data_.ptr;
-    data_.ptr = nullptr;
+    data_.ptr = p;
     if (old != nullptr)
       static_cast<D&>(data_)(old);
-    data_.ptr = p;
   }
 
   T* get() const { return data_.ptr; }
@@ -300,25 +228,25 @@
 // 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
+// std::default_delete, 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> >
+template <class T, class D = std::default_delete<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);
+  static_assert(base::internal::IsNotRefCounted<T>::value,
+                "T is a refcounted type and needs a scoped_refptr");
 
  public:
   // The element and deleter types.
-  typedef T element_type;
-  typedef D deleter_type;
+  using element_type = T;
+  using deleter_type = D;
 
   // Constructor.  Defaults to initializing with nullptr.
   scoped_ptr() : impl_(nullptr) {}
@@ -330,44 +258,87 @@
   scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
 
   // Constructor.  Allows construction from a nullptr.
-  scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+  scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
 
-  // Constructor.  Allows construction from a scoped_ptr rvalue for a
+  // Move constructor.
+  //
+  // IMPLEMENTATION NOTE: Clang requires a move constructor to be defined (and
+  // not just the conversion constructor) in order to warn on pessimizing moves.
+  // The requirements for the move constructor are specified in C++11
+  // 20.7.1.2.1.15-17, which has some subtleties around reference deleters. As
+  // we don't support reference (or move-only) deleters, the post conditions are
+  // trivially true: we always copy construct the deleter from other's deleter.
+  scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
+
+  // Conversion 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);
+  // IMPLEMENTATION NOTE: C++ 20.7.1.2.1.19 requires this constructor to only
+  // participate in overload resolution if all the following are true:
+  // - U is implicitly convertible to T: this is important for 2 reasons:
+  //     1. So type traits don't incorrectly return true, e.g.
+  //          std::is_convertible<scoped_ptr<Base>, scoped_ptr<Derived>>::value
+  //        should be false.
+  //     2. To make sure code like this compiles:
+  //        void F(scoped_ptr<int>);
+  //        void F(scoped_ptr<Base>);
+  //        // Ambiguous since both conversion constructors match.
+  //        F(scoped_ptr<Derived>());
+  // - U is not an array type: to prevent conversions from scoped_ptr<T[]> to
+  //   scoped_ptr<T>.
+  // - D is a reference type and E is the same type, or D is not a reference
+  //   type and E is implicitly convertible to D: again, we don't support
+  //   reference deleters, so we only worry about the latter requirement.
+  template <typename U,
+            typename E,
+            typename std::enable_if<!std::is_array<U>::value &&
+                                    std::is_convertible<U*, T*>::value &&
+                                    std::is_convertible<E, D>::value>::type* =
+                nullptr>
+  scoped_ptr(scoped_ptr<U, E>&& other)
+      : impl_(&other.impl_) {}
+
+  // operator=.
+  //
+  // IMPLEMENTATION NOTE: Unlike the move constructor, Clang does not appear to
+  // require a move assignment operator to trigger the pessimizing move warning:
+  // in this case, the warning triggers when moving a temporary. For consistency
+  // with the move constructor, we define it anyway. C++11 20.7.1.2.3.1-3
+  // defines several requirements around this: like the move constructor, the
+  // requirements are simplified by the fact that we don't support move-only or
+  // reference deleters.
+  scoped_ptr& operator=(scoped_ptr&& rhs) {
+    impl_.TakeState(&rhs.impl_);
+    return *this;
   }
 
   // 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);
+  // the normal move assignment operator. C++11 20.7.1.2.3.4-7 contains the
+  // requirement for this operator, but like the conversion constructor, the
+  // requirements are greatly simplified by not supporting move-only or
+  // reference deleters.
+  template <typename U,
+            typename E,
+            typename std::enable_if<!std::is_array<U>::value &&
+                                    std::is_convertible<U*, T*>::value &&
+                                    // Note that this really should be
+                                    // std::is_assignable, but <type_traits>
+                                    // appears to be missing this on some
+                                    // platforms. This is close enough (though
+                                    // it's not the same).
+                                    std::is_convertible<D, E>::value>::type* =
+                nullptr>
+  scoped_ptr& operator=(scoped_ptr<U, E>&& rhs) {
     impl_.TakeState(&rhs.impl_);
     return *this;
   }
 
   // operator=.  Allows assignment from a nullptr. Deletes the currently owned
   // object, if any.
-  scoped_ptr& operator=(decltype(nullptr)) {
+  scoped_ptr& operator=(std::nullptr_t) {
     reset();
     return *this;
   }
@@ -408,12 +379,6 @@
     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_);
@@ -434,13 +399,6 @@
 
   // 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>
@@ -449,8 +407,8 @@
 
  public:
   // The element and deleter types.
-  typedef T element_type;
-  typedef D deleter_type;
+  using element_type = T;
+  using deleter_type = D;
 
   // Constructor.  Defaults to initializing with nullptr.
   scoped_ptr() : impl_(nullptr) {}
@@ -465,13 +423,11 @@
   //   (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.
+  //   to work around this may use const_cast<const T*>().
   explicit scoped_ptr(element_type* array) : impl_(array) {}
 
   // Constructor.  Allows construction from a nullptr.
-  scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+  scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
 
   // Constructor.  Allows construction from a scoped_ptr rvalue.
   scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
@@ -484,7 +440,7 @@
 
   // operator=.  Allows assignment from a nullptr. Deletes the currently owned
   // array, if any.
-  scoped_ptr& operator=(decltype(nullptr)) {
+  scoped_ptr& operator=(std::nullptr_t) {
     reset();
     return *this;
   }
@@ -515,12 +471,6 @@
     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_);
@@ -553,13 +503,6 @@
   // 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
@@ -568,14 +511,82 @@
   p1.swap(p2);
 }
 
+template <class T1, class D1, class T2, class D2>
+bool operator==(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+  return p1.get() == p2.get();
+}
 template <class T, class D>
-bool operator==(T* p1, const scoped_ptr<T, D>& p2) {
-  return p1 == p2.get();
+bool operator==(const scoped_ptr<T, D>& p, std::nullptr_t) {
+  return p.get() == nullptr;
+}
+template <class T, class D>
+bool operator==(std::nullptr_t, const scoped_ptr<T, D>& p) {
+  return p.get() == nullptr;
 }
 
+template <class T1, class D1, class T2, class D2>
+bool operator!=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+  return !(p1 == p2);
+}
 template <class T, class D>
-bool operator!=(T* p1, const scoped_ptr<T, D>& p2) {
-  return p1 != p2.get();
+bool operator!=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+  return !(p == nullptr);
+}
+template <class T, class D>
+bool operator!=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+  return !(p == nullptr);
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator<(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+  return p1.get() < p2.get();
+}
+template <class T, class D>
+bool operator<(const scoped_ptr<T, D>& p, std::nullptr_t) {
+  return p.get() < nullptr;
+}
+template <class T, class D>
+bool operator<(std::nullptr_t, const scoped_ptr<T, D>& p) {
+  return nullptr < p.get();
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator>(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+  return p2 < p1;
+}
+template <class T, class D>
+bool operator>(const scoped_ptr<T, D>& p, std::nullptr_t) {
+  return nullptr < p;
+}
+template <class T, class D>
+bool operator>(std::nullptr_t, const scoped_ptr<T, D>& p) {
+  return p < nullptr;
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator<=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+  return !(p1 > p2);
+}
+template <class T, class D>
+bool operator<=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+  return !(p > nullptr);
+}
+template <class T, class D>
+bool operator<=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+  return !(nullptr > p);
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator>=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+  return !(p1 < p2);
+}
+template <class T, class D>
+bool operator>=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+  return !(p < nullptr);
+}
+template <class T, class D>
+bool operator>=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+  return !(nullptr < p);
 }
 
 // A function to convert T* into scoped_ptr<T>
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
index 766f444..b26182a 100644
--- a/base/memory/scoped_ptr_unittest.cc
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -84,7 +84,7 @@
 int OverloadedNewAndDelete::g_delete_count = 0;
 
 scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
-  return logger.Pass();
+  return logger;
 }
 
 void GrabAndDrop(scoped_ptr<ConDecLogger> logger) {
@@ -102,8 +102,8 @@
   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);
+  static_assert(sizeof(int*) >= sizeof(scoped_ptr<int>),
+                "scoped_ptr shouldn't be larger than the raw pointer");
 
   {
     scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
@@ -146,25 +146,25 @@
   }
   EXPECT_EQ(0, constructed);
 
-  // Test swap(), == and !=
+  // Test swap().
   {
     scoped_ptr<ConDecLogger> scoper1;
     scoped_ptr<ConDecLogger> scoper2;
-    EXPECT_TRUE(scoper1 == scoper2.get());
-    EXPECT_FALSE(scoper1 != scoper2.get());
+    EXPECT_TRUE(scoper1.get() == scoper2.get());
+    EXPECT_FALSE(scoper1.get() != 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());
+    EXPECT_FALSE(scoper1.get() == scoper2.get());
+    EXPECT_TRUE(scoper1.get() != 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_FALSE(scoper1.get() == scoper2.get());
+    EXPECT_TRUE(scoper1.get() != scoper2.get());
   }
   EXPECT_EQ(0, constructed);
 }
@@ -178,7 +178,7 @@
     EXPECT_EQ(1, constructed);
     EXPECT_TRUE(scoper.get());
 
-    scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass());
+    scoped_ptr<ConDecLoggerParent> scoper_parent(std::move(scoper));
     EXPECT_EQ(1, constructed);
     EXPECT_TRUE(scoper_parent.get());
     EXPECT_FALSE(scoper.get());
@@ -196,7 +196,7 @@
     EXPECT_TRUE(scoper.get());
 
     scoped_ptr<ConDecLoggerParent> scoper_parent;
-    scoper_parent = scoper.Pass();
+    scoper_parent = std::move(scoper);
     EXPECT_EQ(1, constructed);
     EXPECT_TRUE(scoper_parent.get());
     EXPECT_FALSE(scoper.get());
@@ -209,7 +209,7 @@
     EXPECT_EQ(1, constructed);
     EXPECT_TRUE(scoper.get());
 
-    scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass());
+    scoped_ptr<const ConDecLogger> scoper_const(std::move(scoper));
     EXPECT_EQ(1, constructed);
     EXPECT_TRUE(scoper_const.get());
     EXPECT_FALSE(scoper.get());
@@ -227,7 +227,7 @@
     EXPECT_TRUE(scoper.get());
 
     scoped_ptr<const ConDecLogger> scoper_const;
-    scoper_const = scoper.Pass();
+    scoper_const = std::move(scoper);
     EXPECT_EQ(1, constructed);
     EXPECT_TRUE(scoper_const.get());
     EXPECT_FALSE(scoper.get());
@@ -251,7 +251,7 @@
     EXPECT_EQ(0, alternate_deletes);
 
     // Test this compiles and correctly overwrites the deleter state.
-    scoper = scoper_child.Pass();
+    scoper = std::move(scoper_child);
     EXPECT_TRUE(scoper);
     EXPECT_FALSE(scoper_child);
     EXPECT_EQ(1, deletes);
@@ -267,7 +267,8 @@
     EXPECT_TRUE(scoper_child);
     EXPECT_EQ(1, deletes);
     EXPECT_EQ(1, alternate_deletes);
-    scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass());
+    scoped_ptr<double, CountingDeleter> scoper_construct(
+        std::move(scoper_child));
     EXPECT_TRUE(scoper_construct);
     EXPECT_FALSE(scoper_child);
     EXPECT_EQ(1, deletes);
@@ -327,12 +328,12 @@
   }
   EXPECT_EQ(0, constructed);
 
-  // Test swap(), ==, !=, and type-safe Boolean.
+  // Test swap() and type-safe Boolean.
   {
     scoped_ptr<ConDecLogger[]> scoper1;
     scoped_ptr<ConDecLogger[]> scoper2;
-    EXPECT_TRUE(scoper1 == scoper2.get());
-    EXPECT_FALSE(scoper1 != scoper2.get());
+    EXPECT_TRUE(scoper1.get() == scoper2.get());
+    EXPECT_FALSE(scoper1.get() != scoper2.get());
 
     ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
     for (int i = 0; i < kNumLoggers; ++i) {
@@ -343,14 +344,14 @@
     EXPECT_EQ(loggers, scoper1.get());
     EXPECT_FALSE(scoper2);
     EXPECT_FALSE(scoper2.get());
-    EXPECT_FALSE(scoper1 == scoper2.get());
-    EXPECT_TRUE(scoper1 != scoper2.get());
+    EXPECT_FALSE(scoper1.get() == scoper2.get());
+    EXPECT_TRUE(scoper1.get() != 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_FALSE(scoper1.get() == scoper2.get());
+    EXPECT_TRUE(scoper1.get() != scoper2.get());
   }
   EXPECT_EQ(0, constructed);
 
@@ -363,13 +364,13 @@
     }
     EXPECT_EQ(kNumLoggers, constructed);
 
-    // Test Pass() with constructor;
-    scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass());
+    // Test moving with constructor;
+    scoped_ptr<ConDecLogger[]> scoper2(std::move(scoper));
     EXPECT_EQ(kNumLoggers, constructed);
 
-    // Test Pass() with assignment;
+    // Test moving with assignment;
     scoped_ptr<ConDecLogger[]> scoper3;
-    scoper3 = scoper2.Pass();
+    scoper3 = std::move(scoper2);
     EXPECT_EQ(kNumLoggers, constructed);
     EXPECT_FALSE(scoper);
     EXPECT_FALSE(scoper2);
@@ -378,27 +379,29 @@
   EXPECT_EQ(0, constructed);
 }
 
-TEST(ScopedPtrTest, PassBehavior) {
+TEST(ScopedPtrTest, MoveBehavior) {
   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());
+    // Test moving with constructor;
+    scoped_ptr<ConDecLogger> scoper2(std::move(scoper));
     EXPECT_EQ(1, constructed);
 
-    // Test Pass() with assignment;
+    // Test moving with assignment;
     scoped_ptr<ConDecLogger> scoper3;
-    scoper3 = scoper2.Pass();
+    scoper3 = std::move(scoper2);
     EXPECT_EQ(1, constructed);
     EXPECT_FALSE(scoper.get());
     EXPECT_FALSE(scoper2.get());
     EXPECT_TRUE(scoper3.get());
   }
 
-  // Test uncaught Pass() does not have side effects.
+  // Test uncaught Pass() does not have side effects, because Pass()
+  // is implemented by std::move().
+  // TODO(danakj): Remove this test case when we remove Pass().
   {
     ConDecLogger* logger = new ConDecLogger(&constructed);
     scoped_ptr<ConDecLogger> scoper(logger);
@@ -419,7 +422,7 @@
     EXPECT_EQ(1, constructed);
 
     // Should auto-destruct logger by end of scope.
-    GrabAndDrop(scoper.Pass());
+    GrabAndDrop(std::move(scoper));
     EXPECT_FALSE(scoper.get());
   }
   EXPECT_EQ(0, constructed);
@@ -434,7 +437,7 @@
     scoped_ptr<ConDecLogger> scoper(logger);
     EXPECT_EQ(1, constructed);
 
-    PassThru(scoper.Pass());
+    PassThru(std::move(scoper));
     EXPECT_FALSE(scoper.get());
   }
   EXPECT_EQ(0, constructed);
@@ -446,7 +449,7 @@
     EXPECT_EQ(1, constructed);
 
     // Should auto-destruct logger by end of scope.
-    PassThru(scoper.Pass());
+    PassThru(std::move(scoper));
     EXPECT_FALSE(scoper.get());
   }
   EXPECT_EQ(0, constructed);
@@ -537,8 +540,8 @@
     // 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();
+    scoped_ptr<double, CountingDeleter> scoper3(std::move(scoper2));
+    scoper = std::move(scoper3);
     EXPECT_EQ(1, deletes);
 
     scoper2.reset(&dummy_value2);
@@ -549,33 +552,33 @@
   EXPECT_EQ(1, deletes);
   EXPECT_EQ(3, alternate_deletes);
 
-  // Test swap(), ==, !=, and type-safe Boolean.
+  // 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());
+    EXPECT_TRUE(scoper1.get() == scoper2.get());
+    EXPECT_FALSE(scoper1.get() != 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());
+    EXPECT_FALSE(scoper1.get() == scoper2.get());
+    EXPECT_TRUE(scoper1.get() != 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());
+    EXPECT_FALSE(scoper1.get() == scoper2.get());
+    EXPECT_TRUE(scoper1.get() != 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
+// coverage of reset/release/move operations as that is redundant with the
 // above.
 TEST(ScopedPtrTest, OverloadedNewAndDelete) {
   {
@@ -583,7 +586,7 @@
     scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete());
     EXPECT_TRUE(scoper.get());
 
-    scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass());
+    scoped_ptr<OverloadedNewAndDelete> scoper2(std::move(scoper));
   }
   EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
   EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
@@ -632,55 +635,15 @@
   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 move works.
+  scoped_ptr<Super> super1 = std::move(sub1);
+  super1 = std::move(sub2);
 
   // 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) {
@@ -693,3 +656,182 @@
 
   EXPECT_EQ(s2.str(), s1.str());
 }
+
+TEST(ScopedPtrTest, ReferenceCycle) {
+  struct StructB;
+  struct StructA {
+    scoped_ptr<StructB> b;
+  };
+
+  struct StructB {
+    scoped_ptr<StructA> a;
+  };
+
+  // Create a reference cycle.
+  StructA* a = new StructA;
+  a->b.reset(new StructB);
+  a->b->a.reset(a);
+
+  // Break the cycle by calling reset(). This will cause |a| (and hence, |a->b|)
+  // to be deleted before the call to reset() returns. This tests that the
+  // implementation of scoped_ptr::reset() doesn't access |this| after it
+  // deletes the underlying pointer. This behaviour is consistent with the
+  // definition of unique_ptr::reset in C++11.
+  a->b.reset();
+
+  // Go again, but this time, break the cycle by invoking |a|'s destructor. This
+  // tests that the implementation of ~scoped_ptr doesn't infinitely recurse
+  // into the destructors of |a| and |a->b|. Note, deleting |a| instead will
+  // cause |a| to be double-free'd because |a->b| owns |a| and deletes it via
+  // its destructor.
+  a = new StructA;
+  a->b.reset(new StructB);
+  a->b->a.reset(a);
+  a->~StructA();
+}
+
+TEST(ScopedPtrTest, Operators) {
+  struct Parent {};
+  struct Child : public Parent {};
+
+  scoped_ptr<Parent> p(new Parent);
+  scoped_ptr<Parent> p2(new Parent);
+  scoped_ptr<Child> c(new Child);
+  scoped_ptr<Parent> pnull;
+
+  // Operator==.
+  EXPECT_TRUE(p == p);
+  EXPECT_FALSE(p == c);
+  EXPECT_FALSE(p == p2);
+  EXPECT_FALSE(p == pnull);
+
+  EXPECT_FALSE(p == nullptr);
+  EXPECT_FALSE(nullptr == p);
+  EXPECT_TRUE(pnull == nullptr);
+  EXPECT_TRUE(nullptr == pnull);
+
+  // Operator!=.
+  EXPECT_FALSE(p != p);
+  EXPECT_TRUE(p != c);
+  EXPECT_TRUE(p != p2);
+  EXPECT_TRUE(p != pnull);
+
+  EXPECT_TRUE(p != nullptr);
+  EXPECT_TRUE(nullptr != p);
+  EXPECT_FALSE(pnull != nullptr);
+  EXPECT_FALSE(nullptr != pnull);
+
+  // Compare two scoped_ptr<T>.
+  EXPECT_EQ(p.get() < p2.get(), p < p2);
+  EXPECT_EQ(p.get() <= p2.get(), p <= p2);
+  EXPECT_EQ(p.get() > p2.get(), p > p2);
+  EXPECT_EQ(p.get() >= p2.get(), p >= p2);
+  EXPECT_EQ(p2.get() < p.get(), p2 < p);
+  EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
+  EXPECT_EQ(p2.get() > p.get(), p2 > p);
+  EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
+
+  // And convertible scoped_ptr<T> and scoped_ptr<U>.
+  EXPECT_EQ(p.get() < c.get(), p < c);
+  EXPECT_EQ(p.get() <= c.get(), p <= c);
+  EXPECT_EQ(p.get() > c.get(), p > c);
+  EXPECT_EQ(p.get() >= c.get(), p >= c);
+  EXPECT_EQ(c.get() < p.get(), c < p);
+  EXPECT_EQ(c.get() <= p.get(), c <= p);
+  EXPECT_EQ(c.get() > p.get(), c > p);
+  EXPECT_EQ(c.get() >= p.get(), c >= p);
+
+  // Compare to nullptr.
+  EXPECT_TRUE(p > nullptr);
+  EXPECT_FALSE(nullptr > p);
+  EXPECT_FALSE(pnull > nullptr);
+  EXPECT_FALSE(nullptr > pnull);
+
+  EXPECT_TRUE(p >= nullptr);
+  EXPECT_FALSE(nullptr >= p);
+  EXPECT_TRUE(pnull >= nullptr);
+  EXPECT_TRUE(nullptr >= pnull);
+
+  EXPECT_FALSE(p < nullptr);
+  EXPECT_TRUE(nullptr < p);
+  EXPECT_FALSE(pnull < nullptr);
+  EXPECT_FALSE(nullptr < pnull);
+
+  EXPECT_FALSE(p <= nullptr);
+  EXPECT_TRUE(nullptr <= p);
+  EXPECT_TRUE(pnull <= nullptr);
+  EXPECT_TRUE(nullptr <= pnull);
+};
+
+TEST(ScopedPtrTest, ArrayOperators) {
+  struct Parent {};
+  struct Child : public Parent {};
+
+  scoped_ptr<Parent[]> p(new Parent[1]);
+  scoped_ptr<Parent[]> p2(new Parent[1]);
+  scoped_ptr<Child[]> c(new Child[1]);
+  scoped_ptr<Parent[]> pnull;
+
+  // Operator==.
+  EXPECT_TRUE(p == p);
+  EXPECT_FALSE(p == c);
+  EXPECT_FALSE(p == p2);
+  EXPECT_FALSE(p == pnull);
+
+  EXPECT_FALSE(p == nullptr);
+  EXPECT_FALSE(nullptr == p);
+  EXPECT_TRUE(pnull == nullptr);
+  EXPECT_TRUE(nullptr == pnull);
+
+  // Operator!=.
+  EXPECT_FALSE(p != p);
+  EXPECT_TRUE(p != c);
+  EXPECT_TRUE(p != p2);
+  EXPECT_TRUE(p != pnull);
+
+  EXPECT_TRUE(p != nullptr);
+  EXPECT_TRUE(nullptr != p);
+  EXPECT_FALSE(pnull != nullptr);
+  EXPECT_FALSE(nullptr != pnull);
+
+  // Compare two scoped_ptr<T>.
+  EXPECT_EQ(p.get() < p2.get(), p < p2);
+  EXPECT_EQ(p.get() <= p2.get(), p <= p2);
+  EXPECT_EQ(p.get() > p2.get(), p > p2);
+  EXPECT_EQ(p.get() >= p2.get(), p >= p2);
+  EXPECT_EQ(p2.get() < p.get(), p2 < p);
+  EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
+  EXPECT_EQ(p2.get() > p.get(), p2 > p);
+  EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
+
+  // And convertible scoped_ptr<T> and scoped_ptr<U>.
+  EXPECT_EQ(p.get() < c.get(), p < c);
+  EXPECT_EQ(p.get() <= c.get(), p <= c);
+  EXPECT_EQ(p.get() > c.get(), p > c);
+  EXPECT_EQ(p.get() >= c.get(), p >= c);
+  EXPECT_EQ(c.get() < p.get(), c < p);
+  EXPECT_EQ(c.get() <= p.get(), c <= p);
+  EXPECT_EQ(c.get() > p.get(), c > p);
+  EXPECT_EQ(c.get() >= p.get(), c >= p);
+
+  // Compare to nullptr.
+  EXPECT_TRUE(p > nullptr);
+  EXPECT_FALSE(nullptr > p);
+  EXPECT_FALSE(pnull > nullptr);
+  EXPECT_FALSE(nullptr > pnull);
+
+  EXPECT_TRUE(p >= nullptr);
+  EXPECT_FALSE(nullptr >= p);
+  EXPECT_TRUE(pnull >= nullptr);
+  EXPECT_TRUE(nullptr >= pnull);
+
+  EXPECT_FALSE(p < nullptr);
+  EXPECT_TRUE(nullptr < p);
+  EXPECT_FALSE(pnull < nullptr);
+  EXPECT_FALSE(nullptr < pnull);
+
+  EXPECT_FALSE(p <= nullptr);
+  EXPECT_TRUE(nullptr <= p);
+  EXPECT_TRUE(pnull <= nullptr);
+  EXPECT_TRUE(nullptr <= pnull);
+}
diff --git a/base/memory/scoped_ptr_unittest.nc b/base/memory/scoped_ptr_unittest.nc
index b62703c..ede8e2f 100644
--- a/base/memory/scoped_ptr_unittest.nc
+++ b/base/memory/scoped_ptr_unittest.nc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/ref_counted.h"
diff --git a/base/memory/scoped_vector.h b/base/memory/scoped_vector.h
index 173ea5a..5bfd94e 100644
--- a/base/memory/scoped_vector.h
+++ b/base/memory/scoped_vector.h
@@ -15,9 +15,12 @@
 
 // ScopedVector wraps a vector deleting the elements from its
 // destructor.
+//
+// TODO(http://crbug.com/554289): DEPRECATED: Use std::vector instead (now that
+// we have support for moveable types inside containers).
 template <class T>
 class ScopedVector {
-  MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
+  MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector)
 
  public:
   typedef typename std::vector<T*>::allocator_type allocator_type;
@@ -36,10 +39,10 @@
 
   ScopedVector() {}
   ~ScopedVector() { clear(); }
-  ScopedVector(RValue other) { swap(*other.object); }
+  ScopedVector(ScopedVector&& other) { swap(other); }
 
-  ScopedVector& operator=(RValue rhs) {
-    swap(*rhs.object);
+  ScopedVector& operator=(ScopedVector&& rhs) {
+    swap(rhs);
     return *this;
   }
 
@@ -106,6 +109,10 @@
     return v_.insert(position, x);
   }
 
+  iterator insert(iterator position, scoped_ptr<T> x) {
+    return v_.insert(position, x.release());
+  }
+
   // Lets the ScopedVector take ownership of elements in [first,last).
   template<typename InputIterator>
   void insert(iterator position, InputIterator first, InputIterator last) {
diff --git a/base/memory/scoped_vector_unittest.cc b/base/memory/scoped_vector_unittest.cc
index 220cfb0..4dee9c9 100644
--- a/base/memory/scoped_vector_unittest.cc
+++ b/base/memory/scoped_vector_unittest.cc
@@ -24,7 +24,8 @@
   };
 
   ~LifeCycleObject() {
-    observer_->OnLifeCycleDestroy(this);
+    if (observer_)
+      observer_->OnLifeCycleDestroy(this);
   }
 
  private:
@@ -35,6 +36,10 @@
     observer_->OnLifeCycleConstruct(this);
   }
 
+  void DisconnectObserver() {
+    observer_ = nullptr;
+  }
+
   Observer* observer_;
 
   DISALLOW_COPY_AND_ASSIGN(LifeCycleObject);
@@ -62,7 +67,13 @@
 class LifeCycleWatcher : public LifeCycleObject::Observer {
  public:
   LifeCycleWatcher() : life_cycle_state_(LC_INITIAL) {}
-  ~LifeCycleWatcher() override {}
+  ~LifeCycleWatcher() override {
+    // Stop watching the watched object. Without this, the object's destructor
+    // will call into OnLifeCycleDestroy when destructed, which happens after
+    // this destructor has finished running.
+    if (constructed_life_cycle_object_)
+      constructed_life_cycle_object_->DisconnectObserver();
+  }
 
   // Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this
   // LifeCycleWatcher.
diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h
index d76e01c..18416c0 100644
--- a/base/memory/shared_memory.h
+++ b/base/memory/shared_memory.h
@@ -17,6 +17,7 @@
 
 #include "base/base_export.h"
 #include "base/basictypes.h"
+#include "base/memory/shared_memory_handle.h"
 #include "base/process/process_handle.h"
 
 #if defined(OS_POSIX)
@@ -29,41 +30,30 @@
 
 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) {}
+struct BASE_EXPORT SharedMemoryCreateOptions {
+  SharedMemoryCreateOptions();
 
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The type of OS primitive that should back the SharedMemory object.
+  SharedMemoryHandle::Type type;
+#else
   // 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;
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
+  // Size of the shared memory object to be created.
+  // When opening an existing object, this has no effect.
+  size_t size;
 
   // If true, mappings might need to be made executable later.
   bool executable;
@@ -92,12 +82,13 @@
   // 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);
+  SharedMemory(const 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,
+  SharedMemory(const SharedMemoryHandle& handle,
+               bool read_only,
                ProcessHandle process);
 
   // Closes any open files.
@@ -116,6 +107,23 @@
   // Returns the maximum number of handles that can be open at once per process.
   static size_t GetHandleLimit();
 
+  // Duplicates The underlying OS primitive. Returns NULLHandle() on failure.
+  // The caller is responsible for destroying the duplicated OS primitive.
+  static SharedMemoryHandle DuplicateHandle(const SharedMemoryHandle& handle);
+
+#if defined(OS_POSIX)
+  // This method requires that the SharedMemoryHandle is backed by a POSIX fd.
+  static int GetFdFromSharedMemoryHandle(const SharedMemoryHandle& handle);
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+  // Gets the size of the shared memory region referred to by |handle|.
+  // Returns false on a failure to determine the size. On success, populates the
+  // output variable |size|.
+  static bool GetSizeFromSharedMemoryHandle(const SharedMemoryHandle& handle,
+                                            size_t* size);
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
   // Creates a shared memory object as described by the options struct.
   // Returns true on success and false on failure.
   bool Create(const SharedMemoryCreateOptions& options);
@@ -124,6 +132,16 @@
   // Returns true on success and false on failure.
   bool CreateAndMapAnonymous(size_t size);
 
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // These two methods are analogs of CreateAndMapAnonymous and CreateAnonymous
+  // that force the underlying OS primitive to be a POSIX fd. Do not add new
+  // uses of these methods unless absolutely necessary, since constructing a
+  // fd-backed SharedMemory object frequently takes 100ms+.
+  // http://crbug.com/466437.
+  bool CreateAndMapAnonymousPosix(size_t size);
+  bool CreateAnonymousPosix(size_t size);
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
   // Creates an anonymous shared memory segment of size size.
   // Returns true on success and false on failure.
   bool CreateAnonymous(size_t size) {
@@ -132,6 +150,7 @@
     return Create(options);
   }
 
+#if !defined(OS_MACOSX) || defined(OS_IOS)
   // DEPRECATED (crbug.com/345734):
   // Creates or opens a shared memory segment based on a name.
   // If open_existing is true, and the shared memory already exists,
@@ -156,6 +175,7 @@
   // If read_only is true, opens for read-only access.
   // Returns true on success, false on failure.
   bool Open(const std::string& name, bool read_only);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
 
   // Maps the shared memory into the caller's address space.
   // Returns true on success, false otherwise.  The memory address
@@ -185,21 +205,13 @@
 
   // 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_; }
+  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.
@@ -253,27 +265,13 @@
     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)
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID)
   bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly);
+#if !(defined(OS_MACOSX) && !defined(OS_IOS))
   bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
 #endif
-  void LockOrUnlockCommon(int function);
-#endif  // defined(OS_POSIX) && !defined(OS_NACL)
+#endif  // defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID)
   enum ShareMode {
     SHARE_READONLY,
     SHARE_CURRENT_MODE,
@@ -286,41 +284,26 @@
 #if defined(OS_WIN)
   std::wstring       name_;
   HANDLE             mapped_file_;
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+  // The OS primitive that backs the shared memory region.
+  SharedMemoryHandle shm_;
+
+  // The mechanism by which the memory is mapped. Only valid if |memory_| is not
+  // |nullptr|.
+  SharedMemoryHandle::Type mapped_memory_mechanism_;
+
+  int readonly_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_handle.h b/base/memory/shared_memory_handle.h
new file mode 100644
index 0000000..49398a4
--- /dev/null
+++ b/base/memory/shared_memory_handle.h
@@ -0,0 +1,199 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
+#define BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include "base/process/process_handle.h"
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach.h>
+#include <sys/types.h>
+#include "base/base_export.h"
+#include "base/file_descriptor_posix.h"
+#include "base/macros.h"
+#include "base/process/process_handle.h"
+#elif defined(OS_POSIX)
+#include <sys/types.h>
+#include "base/file_descriptor_posix.h"
+#endif
+
+namespace base {
+
+class Pickle;
+
+// SharedMemoryHandle is a platform specific type which represents
+// the underlying OS handle to a shared memory segment.
+#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+typedef FileDescriptor SharedMemoryHandle;
+#elif defined(OS_WIN)
+class BASE_EXPORT SharedMemoryHandle {
+ public:
+  // The default constructor returns an invalid SharedMemoryHandle.
+  SharedMemoryHandle();
+  SharedMemoryHandle(HANDLE h, base::ProcessId pid);
+
+  // Standard copy constructor. The new instance shares the underlying OS
+  // primitives.
+  SharedMemoryHandle(const SharedMemoryHandle& handle);
+
+  // Standard assignment operator. The updated instance shares the underlying
+  // OS primitives.
+  SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
+
+  // Comparison operators.
+  bool operator==(const SharedMemoryHandle& handle) const;
+  bool operator!=(const SharedMemoryHandle& handle) const;
+
+  // Closes the underlying OS resources.
+  void Close() const;
+
+  // Whether the underlying OS primitive is valid.
+  bool IsValid() const;
+
+  // Whether |pid_| is the same as the current process's id.
+  bool BelongsToCurrentProcess() const;
+
+  // Whether handle_ needs to be duplicated into the destination process when
+  // an instance of this class is passed over a Chrome IPC channel.
+  bool NeedsBrokering() const;
+
+  HANDLE GetHandle() const;
+  base::ProcessId GetPID() const;
+
+ private:
+  HANDLE handle_;
+
+  // The process in which |handle_| is valid and can be used. If |handle_| is
+  // invalid, this will be kNullProcessId.
+  base::ProcessId pid_;
+};
+#else
+class BASE_EXPORT SharedMemoryHandle {
+ public:
+  // The values of these enums must not change, as they are used by the
+  // histogram OSX.SharedMemory.Mechanism.
+  enum Type {
+    // The SharedMemoryHandle is backed by a POSIX fd.
+    POSIX,
+    // The SharedMemoryHandle is backed by the Mach primitive "memory object".
+    MACH,
+  };
+  static const int TypeMax = 2;
+
+  // The format that should be used to transmit |Type| over the wire.
+  typedef int TypeWireFormat;
+
+  // The default constructor returns an invalid SharedMemoryHandle.
+  SharedMemoryHandle();
+
+  // Constructs a SharedMemoryHandle backed by the components of a
+  // FileDescriptor. The newly created instance has the same ownership semantics
+  // as base::FileDescriptor. This typically means that the SharedMemoryHandle
+  // takes ownership of the |fd| if |auto_close| is true. Unfortunately, it's
+  // common for existing code to make shallow copies of SharedMemoryHandle, and
+  // the one that is finally passed into a base::SharedMemory is the one that
+  // "consumes" the fd.
+  explicit SharedMemoryHandle(const base::FileDescriptor& file_descriptor);
+  SharedMemoryHandle(int fd, bool auto_close);
+
+  // Makes a Mach-based SharedMemoryHandle of the given size. On error,
+  // subsequent calls to IsValid() return false.
+  explicit SharedMemoryHandle(mach_vm_size_t size);
+
+  // Makes a Mach-based SharedMemoryHandle from |memory_object|, a named entry
+  // in the task with process id |pid|. The memory region has size |size|.
+  SharedMemoryHandle(mach_port_t memory_object,
+                     mach_vm_size_t size,
+                     base::ProcessId pid);
+
+  // Standard copy constructor. The new instance shares the underlying OS
+  // primitives.
+  SharedMemoryHandle(const SharedMemoryHandle& handle);
+
+  // Standard assignment operator. The updated instance shares the underlying
+  // OS primitives.
+  SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
+
+  // Duplicates the underlying OS resources.
+  SharedMemoryHandle Duplicate() const;
+
+  // Comparison operators.
+  bool operator==(const SharedMemoryHandle& handle) const;
+  bool operator!=(const SharedMemoryHandle& handle) const;
+
+  // Returns the type.
+  Type GetType() const;
+
+  // Whether the underlying OS primitive is valid. Once the SharedMemoryHandle
+  // is backed by a valid OS primitive, it becomes immutable.
+  bool IsValid() const;
+
+  // Sets the POSIX fd backing the SharedMemoryHandle. Requires that the
+  // SharedMemoryHandle be backed by a POSIX fd.
+  void SetFileHandle(int fd, bool auto_close);
+
+  // This method assumes that the SharedMemoryHandle is backed by a POSIX fd.
+  // This is eventually no longer going to be true, so please avoid adding new
+  // uses of this method.
+  const FileDescriptor GetFileDescriptor() const;
+
+  // Exposed so that the SharedMemoryHandle can be transported between
+  // processes.
+  mach_port_t GetMemoryObject() const;
+
+  // Returns false on a failure to determine the size. On success, populates the
+  // output variable |size|.
+  bool GetSize(size_t* size) const;
+
+  // The SharedMemoryHandle must be valid.
+  // Returns whether the SharedMemoryHandle was successfully mapped into memory.
+  // On success, |memory| is an output variable that contains the start of the
+  // mapped memory.
+  bool MapAt(off_t offset, size_t bytes, void** memory, bool read_only);
+
+  // Closes the underlying OS primitive.
+  void Close() const;
+
+  void SetOwnershipPassesToIPC(bool ownership_passes);
+  bool OwnershipPassesToIPC() const;
+
+ private:
+  // Shared code between copy constructor and operator=.
+  void CopyRelevantData(const SharedMemoryHandle& handle);
+
+  Type type_;
+
+  // Each instance of a SharedMemoryHandle is backed either by a POSIX fd or a
+  // mach port. |type_| determines the backing member.
+  union {
+    FileDescriptor file_descriptor_;
+
+    struct {
+      mach_port_t memory_object_;
+
+      // The size of the shared memory region when |type_| is MACH. Only
+      // relevant if |memory_object_| is not |MACH_PORT_NULL|.
+      mach_vm_size_t size_;
+
+      // The pid of the process in which |memory_object_| is usable. Only
+      // relevant if |memory_object_| is not |MACH_PORT_NULL|.
+      base::ProcessId pid_;
+
+      // Whether passing this object as a parameter to an IPC message passes
+      // ownership of |memory_object_| to the IPC stack. This is meant to mimic
+      // the behavior of the |auto_close| parameter of FileDescriptor.
+      // Defaults to |false|.
+      bool ownership_passes_to_ipc_;
+    };
+  };
+};
+#endif
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
diff --git a/base/memory/shared_memory_handle_mac.cc b/base/memory/shared_memory_handle_mac.cc
new file mode 100644
index 0000000..12f2f68
--- /dev/null
+++ b/base/memory/shared_memory_handle_mac.cc
@@ -0,0 +1,241 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/shared_memory_handle.h"
+
+#include <mach/mach_vm.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "base/mac/mac_util.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace base {
+
+static_assert(sizeof(SharedMemoryHandle::Type) <=
+                  sizeof(SharedMemoryHandle::TypeWireFormat),
+              "Size of enum SharedMemoryHandle::Type exceeds size of type "
+              "transmitted over wire.");
+
+SharedMemoryHandle::SharedMemoryHandle() : type_(POSIX), file_descriptor_() {}
+
+SharedMemoryHandle::SharedMemoryHandle(
+    const base::FileDescriptor& file_descriptor)
+    : type_(POSIX), file_descriptor_(file_descriptor) {}
+
+SharedMemoryHandle::SharedMemoryHandle(int fd, bool auto_close)
+    : type_(POSIX), file_descriptor_(fd, auto_close) {}
+
+SharedMemoryHandle::SharedMemoryHandle(mach_vm_size_t size) {
+  type_ = MACH;
+  mach_port_t named_right;
+  kern_return_t kr = mach_make_memory_entry_64(
+      mach_task_self(),
+      &size,
+      0,  // Address.
+      MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE,
+      &named_right,
+      MACH_PORT_NULL);  // Parent handle.
+  if (kr != KERN_SUCCESS) {
+    memory_object_ = MACH_PORT_NULL;
+    return;
+  }
+
+  memory_object_ = named_right;
+  size_ = size;
+  pid_ = GetCurrentProcId();
+  ownership_passes_to_ipc_ = false;
+}
+
+SharedMemoryHandle::SharedMemoryHandle(mach_port_t memory_object,
+                                       mach_vm_size_t size,
+                                       base::ProcessId pid)
+    : type_(MACH),
+      memory_object_(memory_object),
+      size_(size),
+      pid_(pid),
+      ownership_passes_to_ipc_(false) {}
+
+SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle)
+    : type_(handle.type_) {
+  CopyRelevantData(handle);
+}
+
+SharedMemoryHandle& SharedMemoryHandle::operator=(
+    const SharedMemoryHandle& handle) {
+  if (this == &handle)
+    return *this;
+
+  type_ = handle.type_;
+  CopyRelevantData(handle);
+  return *this;
+}
+
+SharedMemoryHandle SharedMemoryHandle::Duplicate() const {
+  switch (type_) {
+    case POSIX: {
+      if (!IsValid())
+        return SharedMemoryHandle();
+
+      int duped_fd = HANDLE_EINTR(dup(file_descriptor_.fd));
+      if (duped_fd < 0)
+        return SharedMemoryHandle();
+      return SharedMemoryHandle(duped_fd, true);
+    }
+    case MACH: {
+      if (!IsValid())
+        return SharedMemoryHandle(MACH_PORT_NULL, 0, 0);
+
+      // Increment the ref count.
+      kern_return_t kr = mach_port_mod_refs(mach_task_self(), memory_object_,
+                                            MACH_PORT_RIGHT_SEND, 1);
+      DCHECK_EQ(kr, KERN_SUCCESS);
+      return SharedMemoryHandle(*this);
+    }
+  }
+}
+
+bool SharedMemoryHandle::operator==(const SharedMemoryHandle& handle) const {
+  if (!IsValid() && !handle.IsValid())
+    return true;
+
+  if (type_ != handle.type_)
+    return false;
+
+  switch (type_) {
+    case POSIX:
+      return file_descriptor_ == handle.file_descriptor_;
+    case MACH:
+      return memory_object_ == handle.memory_object_ && size_ == handle.size_ &&
+             pid_ == handle.pid_;
+  }
+}
+
+bool SharedMemoryHandle::operator!=(const SharedMemoryHandle& handle) const {
+  return !(*this == handle);
+}
+
+SharedMemoryHandle::Type SharedMemoryHandle::GetType() const {
+  return type_;
+}
+
+bool SharedMemoryHandle::IsValid() const {
+  switch (type_) {
+    case POSIX:
+      return file_descriptor_.fd >= 0;
+    case MACH:
+      return memory_object_ != MACH_PORT_NULL;
+  }
+}
+
+void SharedMemoryHandle::SetFileHandle(int fd, bool auto_close) {
+  DCHECK(!IsValid());
+  file_descriptor_.fd = fd;
+  file_descriptor_.auto_close = auto_close;
+  type_ = POSIX;
+}
+
+const FileDescriptor SharedMemoryHandle::GetFileDescriptor() const {
+  DCHECK_EQ(type_, POSIX);
+  return file_descriptor_;
+}
+
+mach_port_t SharedMemoryHandle::GetMemoryObject() const {
+  DCHECK_EQ(type_, MACH);
+  return memory_object_;
+}
+
+bool SharedMemoryHandle::GetSize(size_t* size) const {
+  if (!IsValid())
+    return false;
+
+  switch (type_) {
+    case SharedMemoryHandle::POSIX:
+      struct stat st;
+      if (fstat(file_descriptor_.fd, &st) != 0)
+        return false;
+      if (st.st_size < 0)
+        return false;
+      *size = st.st_size;
+      return true;
+    case SharedMemoryHandle::MACH:
+      *size = size_;
+      return true;
+  }
+}
+
+bool SharedMemoryHandle::MapAt(off_t offset,
+                               size_t bytes,
+                               void** memory,
+                               bool read_only) {
+  DCHECK(IsValid());
+  switch (type_) {
+    case SharedMemoryHandle::POSIX:
+      *memory = mmap(nullptr, bytes, PROT_READ | (read_only ? 0 : PROT_WRITE),
+                     MAP_SHARED, file_descriptor_.fd, offset);
+
+      return *memory && *memory != reinterpret_cast<void*>(-1);
+    case SharedMemoryHandle::MACH:
+      // The flag VM_PROT_IS_MASK is only supported on OSX 10.7+.
+      DCHECK(mac::IsOSLionOrLater());
+
+      DCHECK_EQ(pid_, GetCurrentProcId());
+      kern_return_t kr = mach_vm_map(
+          mach_task_self(),
+          reinterpret_cast<mach_vm_address_t*>(memory),    // Output parameter
+          bytes,
+          0,                                               // Alignment mask
+          VM_FLAGS_ANYWHERE,
+          memory_object_,
+          offset,
+          FALSE,                                           // Copy
+          VM_PROT_READ | (read_only ? 0 : VM_PROT_WRITE),  // Current protection
+          VM_PROT_WRITE | VM_PROT_READ | VM_PROT_IS_MASK,  // Maximum protection
+          VM_INHERIT_NONE);
+      return kr == KERN_SUCCESS;
+  }
+}
+
+void SharedMemoryHandle::Close() const {
+  if (!IsValid())
+    return;
+
+  switch (type_) {
+    case POSIX:
+      if (IGNORE_EINTR(close(file_descriptor_.fd)) < 0)
+        DPLOG(ERROR) << "Error closing fd.";
+      break;
+    case MACH:
+      kern_return_t kr = mach_port_deallocate(mach_task_self(), memory_object_);
+      if (kr != KERN_SUCCESS)
+        DPLOG(ERROR) << "Error deallocating mach port: " << kr;
+      break;
+  }
+}
+
+void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
+  DCHECK_EQ(type_, MACH);
+  ownership_passes_to_ipc_ = ownership_passes;
+}
+
+bool SharedMemoryHandle::OwnershipPassesToIPC() const {
+  DCHECK_EQ(type_, MACH);
+  return ownership_passes_to_ipc_;
+}
+
+void SharedMemoryHandle::CopyRelevantData(const SharedMemoryHandle& handle) {
+  switch (type_) {
+    case POSIX:
+      file_descriptor_ = handle.file_descriptor_;
+      break;
+    case MACH:
+      memory_object_ = handle.memory_object_;
+      size_ = handle.size_;
+      pid_ = handle.pid_;
+      ownership_passes_to_ipc_ = handle.ownership_passes_to_ipc_;
+      break;
+  }
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_handle_win.cc b/base/memory/shared_memory_handle_win.cc
new file mode 100644
index 0000000..571e4ef
--- /dev/null
+++ b/base/memory/shared_memory_handle_win.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/memory/shared_memory_handle.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+SharedMemoryHandle::SharedMemoryHandle()
+    : handle_(nullptr), pid_(kNullProcessId) {}
+
+SharedMemoryHandle::SharedMemoryHandle(HANDLE h, base::ProcessId pid)
+    : handle_(h), pid_(pid) {}
+
+SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle)
+    : handle_(handle.handle_), pid_(handle.pid_) {}
+
+SharedMemoryHandle& SharedMemoryHandle::operator=(
+    const SharedMemoryHandle& handle) {
+  if (this == &handle)
+    return *this;
+
+  handle_ = handle.handle_;
+  pid_ = handle.pid_;
+  return *this;
+}
+
+bool SharedMemoryHandle::operator==(const SharedMemoryHandle& handle) const {
+  // Invalid handles are always equal.
+  if (!IsValid() && !handle.IsValid())
+    return true;
+
+  return handle_ == handle.handle_ && pid_ == handle.pid_;
+}
+
+bool SharedMemoryHandle::operator!=(const SharedMemoryHandle& handle) const {
+  return !(*this == handle);
+}
+
+void SharedMemoryHandle::Close() const {
+  DCHECK(handle_ != nullptr);
+  DCHECK(BelongsToCurrentProcess());
+  ::CloseHandle(handle_);
+}
+
+bool SharedMemoryHandle::IsValid() const {
+  return handle_ != nullptr;
+}
+
+bool SharedMemoryHandle::BelongsToCurrentProcess() const {
+  return pid_ == base::GetCurrentProcId();
+}
+
+bool SharedMemoryHandle::NeedsBrokering() const {
+  return false;
+}
+
+HANDLE SharedMemoryHandle::GetHandle() const {
+  return handle_;
+}
+
+base::ProcessId SharedMemoryHandle::GetPID() const {
+  return pid_;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_mac.cc b/base/memory/shared_memory_mac.cc
new file mode 100644
index 0000000..a54d0ba
--- /dev/null
+++ b/base/memory/shared_memory_mac.cc
@@ -0,0 +1,500 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/shared_memory.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <mach/mach_vm.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_mach_vm.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/safe_strerror.h"
+#include "base/process/process_metrics.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/scoped_generic.h"
+#include "base/strings/utf_string_conversions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif  // OS_MACOSX
+
+namespace base {
+
+namespace {
+
+const char kTrialName[] = "MacMemoryMechanism";
+const char kTrialMach[] = "Mach";
+const char kTrialPosix[] = "Posix";
+
+SharedMemoryHandle::Type GetABTestMechanism() {
+  static bool found_group = false;
+  static SharedMemoryHandle::Type group = SharedMemoryHandle::MACH;
+
+  if (found_group)
+    return group;
+
+  const std::string group_name =
+      base::FieldTrialList::FindFullName(kTrialName);
+  if (group_name == kTrialMach) {
+    group = SharedMemoryHandle::MACH;
+    found_group = true;
+  } else if (group_name == kTrialPosix) {
+    group = SharedMemoryHandle::POSIX;
+    found_group = true;
+  } else {
+    group = SharedMemoryHandle::MACH;
+  }
+
+  return group;
+}
+
+// Emits a histogram entry indicating which type of SharedMemory was created.
+void EmitMechanism(SharedMemoryHandle::Type type) {
+  UMA_HISTOGRAM_ENUMERATION("OSX.SharedMemory.Mechanism", type,
+                            SharedMemoryHandle::TypeMax);
+}
+
+// Returns whether the operation succeeded.
+// |new_handle| is an output variable, populated on success. The caller takes
+// ownership of the underlying memory object.
+// |handle| is the handle to copy.
+// If |handle| is already mapped, |mapped_addr| is its mapped location.
+// Otherwise, |mapped_addr| should be |nullptr|.
+bool MakeMachSharedMemoryHandleReadOnly(SharedMemoryHandle* new_handle,
+                                        SharedMemoryHandle handle,
+                                        void* mapped_addr) {
+  if (!handle.IsValid())
+    return false;
+
+  size_t size;
+  CHECK(handle.GetSize(&size));
+
+  // Map if necessary.
+  void* temp_addr = mapped_addr;
+  base::mac::ScopedMachVM scoper;
+  if (!temp_addr) {
+    // Intentionally lower current prot and max prot to |VM_PROT_READ|.
+    kern_return_t kr = mach_vm_map(
+        mach_task_self(), reinterpret_cast<mach_vm_address_t*>(&temp_addr),
+        size, 0, VM_FLAGS_ANYWHERE, handle.GetMemoryObject(), 0, FALSE,
+        VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
+    if (kr != KERN_SUCCESS)
+      return false;
+    scoper.reset(reinterpret_cast<vm_address_t>(temp_addr),
+                 mach_vm_round_page(size));
+  }
+
+  // Make new memory object.
+  mach_port_t named_right;
+  kern_return_t kr = mach_make_memory_entry_64(
+      mach_task_self(), reinterpret_cast<memory_object_size_t*>(&size),
+      reinterpret_cast<memory_object_offset_t>(temp_addr), VM_PROT_READ,
+      &named_right, MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS)
+    return false;
+
+  *new_handle = SharedMemoryHandle(named_right, size, base::GetCurrentProcId());
+  return true;
+}
+
+struct ScopedPathUnlinkerTraits {
+  static FilePath* InvalidValue() { return nullptr; }
+
+  static void Free(FilePath* path) {
+    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+    // is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "466437 SharedMemory::Create::Unlink"));
+    if (unlink(path->value().c_str()))
+      PLOG(WARNING) << "unlink";
+  }
+};
+
+// Unlinks the FilePath when the object is destroyed.
+typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
+
+// Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
+// with the fdopened FILE. |readonly_fd| is populated with the opened fd if
+// options.share_read_only is true. |path| is populated with the location of
+// the file before it was unlinked.
+// Returns false if there's an unhandled failure.
+bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
+                                 ScopedFILE* fp,
+                                 ScopedFD* readonly_fd,
+                                 FilePath* path) {
+  // Q: Why not use the shm_open() etc. APIs?
+  // A: Because they're limited to 4mb on OS X.  FFFFFFFUUUUUUUUUUU
+  FilePath directory;
+  ScopedPathUnlinker path_unlinker;
+  if (GetShmemTempDir(options.executable, &directory)) {
+    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+    // is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "466437 SharedMemory::Create::OpenTemporaryFile"));
+    fp->reset(CreateAndOpenTemporaryFileInDir(directory, path));
+
+    // Deleting the file prevents anyone else from mapping it in (making it
+    // private), and prevents the need for cleanup (once the last fd is
+    // closed, it is truly freed).
+    if (*fp)
+      path_unlinker.reset(path);
+  }
+
+  if (*fp) {
+    if (options.share_read_only) {
+      // TODO(erikchen): Remove ScopedTracker below once
+      // http://crbug.com/466437 is fixed.
+      tracked_objects::ScopedTracker tracking_profile(
+          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+              "466437 SharedMemory::Create::OpenReadonly"));
+      // Also open as readonly so that we can ShareReadOnlyToProcess.
+      readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
+      if (!readonly_fd->is_valid()) {
+        DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
+        fp->reset();
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+    : type(SharedMemoryHandle::MACH),
+      size(0),
+      executable(false),
+      share_read_only(false) {
+  if (mac::IsOSLionOrLater()) {
+    // A/B test the mechanism. Once the experiment is over, this will always be
+    // set to SharedMemoryHandle::MACH.
+    // http://crbug.com/547261
+    type = GetABTestMechanism();
+  } else {
+    // Mach shared memory isn't supported on OSX 10.6 or older.
+    type = SharedMemoryHandle::POSIX;
+  }
+}
+
+SharedMemory::SharedMemory()
+    : mapped_memory_mechanism_(SharedMemoryHandle::POSIX),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0) {}
+
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
+    : shm_(handle),
+      mapped_memory_mechanism_(SharedMemoryHandle::POSIX),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {}
+
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
+                           bool read_only,
+                           ProcessHandle process)
+    : mapped_memory_mechanism_(SharedMemoryHandle::POSIX),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+  // We don't handle this case yet (note the ignored parameter); let's die if
+  // someone comes calling.
+  NOTREACHED();
+}
+
+SharedMemory::~SharedMemory() {
+  Unmap();
+  Close();
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle.IsValid();
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return SharedMemoryHandle();
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  handle.Close();
+}
+
+// static
+size_t SharedMemory::GetHandleLimit() {
+  return GetMaxFds();
+}
+
+// static
+SharedMemoryHandle SharedMemory::DuplicateHandle(
+    const SharedMemoryHandle& handle) {
+  return handle.Duplicate();
+}
+
+// static
+int SharedMemory::GetFdFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle) {
+  return handle.GetFileDescriptor().fd;
+}
+
+bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+  return CreateAnonymous(size) && Map(size);
+}
+
+bool SharedMemory::CreateAndMapAnonymousPosix(size_t size) {
+  return CreateAnonymousPosix(size) && Map(size);
+}
+
+bool SharedMemory::CreateAnonymousPosix(size_t size) {
+  SharedMemoryCreateOptions options;
+  options.type = SharedMemoryHandle::POSIX;
+  options.size = size;
+  return Create(options);
+}
+
+// static
+bool SharedMemory::GetSizeFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle,
+    size_t* size) {
+  return handle.GetSize(size);
+}
+
+// Chromium mostly only uses the unique/private shmem as specified by
+// "name == L"". The exception is in the StatsTable.
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+  // is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "466437 SharedMemory::Create::Start"));
+  DCHECK(!shm_.IsValid());
+  if (options.size == 0) return false;
+
+  if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  EmitMechanism(options.type);
+
+  if (options.type == SharedMemoryHandle::MACH) {
+    shm_ = SharedMemoryHandle(options.size);
+    requested_size_ = options.size;
+    return shm_.IsValid();
+  }
+
+  // This function theoretically can block on the disk. Both profiling of real
+  // users and local instrumentation shows that this is a real problem.
+  // https://code.google.com/p/chromium/issues/detail?id=466437
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  ScopedFILE fp;
+  ScopedFD readonly_fd;
+
+  FilePath path;
+  bool result = CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
+  if (!result)
+    return false;
+
+  if (!fp) {
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+    return false;
+  }
+
+  // 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;
+
+  return PrepareMapFile(std::move(fp), std::move(readonly_fd));
+}
+
+bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+  if (!shm_.IsValid())
+    return false;
+  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+  if (memory_)
+    return false;
+
+  bool success = shm_.MapAt(offset, bytes, &memory_, read_only_);
+  if (success) {
+    mapped_size_ = bytes;
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+                      (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+    mapped_memory_mechanism_ = shm_.GetType();
+  } else {
+    memory_ = NULL;
+  }
+
+  return success;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  switch (mapped_memory_mechanism_) {
+    case SharedMemoryHandle::POSIX:
+      munmap(memory_, mapped_size_);
+      break;
+    case SharedMemoryHandle::MACH:
+      mach_vm_deallocate(mach_task_self(),
+                         reinterpret_cast<mach_vm_address_t>(memory_),
+                         mapped_size_);
+      break;
+  }
+
+  memory_ = NULL;
+  mapped_size_ = 0;
+  return true;
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  switch (shm_.GetType()) {
+    case SharedMemoryHandle::POSIX:
+      return SharedMemoryHandle(shm_.GetFileDescriptor().fd, false);
+    case SharedMemoryHandle::MACH:
+      return shm_;
+  }
+}
+
+void SharedMemory::Close() {
+  shm_.Close();
+  shm_ = SharedMemoryHandle();
+  if (shm_.GetType() == SharedMemoryHandle::POSIX) {
+    if (readonly_mapped_file_ > 0) {
+      if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0)
+        PLOG(ERROR) << "close";
+      readonly_mapped_file_ = -1;
+    }
+  }
+}
+
+bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
+  DCHECK(!shm_.IsValid());
+  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;
+    }
+  }
+
+  int mapped_file = HANDLE_EINTR(dup(fileno(fp.get())));
+  if (mapped_file == -1) {
+    if (errno == EMFILE) {
+      LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
+      return false;
+    } else {
+      NOTREACHED() << "Call to dup failed, errno=" << errno;
+    }
+  }
+  shm_ = SharedMemoryHandle(mapped_file, false);
+  readonly_mapped_file_ = readonly_fd.release();
+
+  return true;
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle* new_handle,
+                                        bool close_self,
+                                        ShareMode share_mode) {
+  if (shm_.GetType() == SharedMemoryHandle::MACH) {
+    DCHECK(shm_.IsValid());
+
+    bool success = false;
+    switch (share_mode) {
+      case SHARE_CURRENT_MODE:
+        *new_handle = shm_.Duplicate();
+        success = true;
+        break;
+      case SHARE_READONLY:
+        success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_);
+        break;
+    }
+
+    if (success)
+      new_handle->SetOwnershipPassesToIPC(true);
+
+    if (close_self) {
+      Unmap();
+      Close();
+    }
+
+    return success;
+  }
+
+  int handle_to_dup = -1;
+  switch (share_mode) {
+    case SHARE_CURRENT_MODE:
+      handle_to_dup = shm_.GetFileDescriptor().fd;
+      break;
+    case SHARE_READONLY:
+      // We could imagine re-opening the file from /dev/fd, but that can't make
+      // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
+      CHECK_GE(readonly_mapped_file_, 0);
+      handle_to_dup = readonly_mapped_file_;
+      break;
+  }
+
+  const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
+  if (new_fd < 0) {
+    if (close_self) {
+      Unmap();
+      Close();
+    }
+    DPLOG(ERROR) << "dup() failed.";
+    return false;
+  }
+
+  new_handle->SetFileHandle(new_fd, true);
+
+  if (close_self) {
+    Unmap();
+    Close();
+  }
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_mac_unittest.cc b/base/memory/shared_memory_mac_unittest.cc
new file mode 100644
index 0000000..1c91834
--- /dev/null
+++ b/base/memory/shared_memory_mac_unittest.cc
@@ -0,0 +1,486 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <servers/bootstrap.h>
+
+#include "base/command_line.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/process_handle.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+namespace {
+
+// Gets the current and maximum protection levels of the memory region.
+// Returns whether the operation was successful.
+// |current| and |max| are output variables only populated on success.
+bool GetProtections(void* address, size_t size, int* current, int* max) {
+  vm_region_info_t region_info;
+  mach_vm_address_t mem_address = reinterpret_cast<mach_vm_address_t>(address);
+  mach_vm_size_t mem_size = size;
+  vm_region_basic_info_64 basic_info;
+
+  region_info = reinterpret_cast<vm_region_recurse_info_t>(&basic_info);
+  vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64;
+  memory_object_name_t memory_object;
+  mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
+
+  kern_return_t kr =
+      mach_vm_region(mach_task_self(), &mem_address, &mem_size, flavor,
+                     region_info, &count, &memory_object);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Failed to get region info.";
+    return false;
+  }
+
+  *current = basic_info.protection;
+  *max = basic_info.max_protection;
+  return true;
+}
+
+// Creates a new SharedMemory with the given |size|, filled with 'a'.
+scoped_ptr<SharedMemory> CreateSharedMemory(int size) {
+  SharedMemoryHandle shm(size);
+  if (!shm.IsValid()) {
+    LOG(ERROR) << "Failed to make SharedMemoryHandle";
+    return nullptr;
+  }
+  scoped_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false));
+  shared_memory->Map(size);
+  memset(shared_memory->memory(), 'a', size);
+  return shared_memory;
+}
+
+static const std::string g_service_switch_name = "service_name";
+
+// Structs used to pass a mach port from client to server.
+struct MachSendPortMessage {
+  mach_msg_header_t header;
+  mach_msg_body_t body;
+  mach_msg_port_descriptor_t data;
+};
+struct MachReceivePortMessage {
+  mach_msg_header_t header;
+  mach_msg_body_t body;
+  mach_msg_port_descriptor_t data;
+  mach_msg_trailer_t trailer;
+};
+
+// Makes the current process into a Mach Server with the given |service_name|.
+mach_port_t BecomeMachServer(const char* service_name) {
+  mach_port_t port;
+  kern_return_t kr = bootstrap_check_in(bootstrap_port, service_name, &port);
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "BecomeMachServer";
+  return port;
+}
+
+// Returns the mach port for the Mach Server with the given |service_name|.
+mach_port_t LookupServer(const char* service_name) {
+  mach_port_t server_port;
+  kern_return_t kr =
+      bootstrap_look_up(bootstrap_port, service_name, &server_port);
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "LookupServer";
+  return server_port;
+}
+
+mach_port_t MakeReceivingPort() {
+  mach_port_t client_port;
+  kern_return_t kr =
+      mach_port_allocate(mach_task_self(),         // our task is acquiring
+                         MACH_PORT_RIGHT_RECEIVE,  // a new receive right
+                         &client_port);            // with this name
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "MakeReceivingPort";
+  return client_port;
+}
+
+// Blocks until a mach message is sent to |server_port|. This mach message
+// must contain a mach port. Returns that mach port.
+mach_port_t ReceiveMachPort(mach_port_t port_to_listen_on) {
+  MachReceivePortMessage recv_msg;
+  mach_msg_header_t* recv_hdr = &(recv_msg.header);
+  recv_hdr->msgh_local_port = port_to_listen_on;
+  recv_hdr->msgh_size = sizeof(recv_msg);
+  kern_return_t kr =
+      mach_msg(recv_hdr,               // message buffer
+               MACH_RCV_MSG,           // option indicating service
+               0,                      // send size
+               recv_hdr->msgh_size,    // size of header + body
+               port_to_listen_on,      // receive name
+               MACH_MSG_TIMEOUT_NONE,  // no timeout, wait forever
+               MACH_PORT_NULL);        // no notification port
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "ReceiveMachPort";
+  mach_port_t other_task_port = recv_msg.data.name;
+  return other_task_port;
+}
+
+// Passes a copy of the send right of |port_to_send| to |receiving_port|.
+void SendMachPort(mach_port_t receiving_port,
+                  mach_port_t port_to_send,
+                  int disposition) {
+  MachSendPortMessage send_msg;
+  mach_msg_header_t* send_hdr;
+  send_hdr = &(send_msg.header);
+  send_hdr->msgh_bits =
+      MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
+  send_hdr->msgh_size = sizeof(send_msg);
+  send_hdr->msgh_remote_port = receiving_port;
+  send_hdr->msgh_local_port = MACH_PORT_NULL;
+  send_hdr->msgh_reserved = 0;
+  send_hdr->msgh_id = 0;
+  send_msg.body.msgh_descriptor_count = 1;
+  send_msg.data.name = port_to_send;
+  send_msg.data.disposition = disposition;
+  send_msg.data.type = MACH_MSG_PORT_DESCRIPTOR;
+  int kr = mach_msg(send_hdr,               // message buffer
+                    MACH_SEND_MSG,          // option indicating send
+                    send_hdr->msgh_size,    // size of header + body
+                    0,                      // receive limit
+                    MACH_PORT_NULL,         // receive name
+                    MACH_MSG_TIMEOUT_NONE,  // no timeout, wait forever
+                    MACH_PORT_NULL);        // no notification port
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "SendMachPort";
+}
+
+std::string CreateRandomServiceName() {
+  return StringPrintf("SharedMemoryMacMultiProcessTest.%llu", RandUint64());
+}
+
+// Sets up the mach communication ports with the server. Returns a port to which
+// the server will send mach objects.
+mach_port_t CommonChildProcessSetUp() {
+  CommandLine cmd_line = *CommandLine::ForCurrentProcess();
+  std::string service_name =
+      cmd_line.GetSwitchValueASCII(g_service_switch_name);
+  mac::ScopedMachSendRight server_port(LookupServer(service_name.c_str()));
+  mach_port_t client_port = MakeReceivingPort();
+
+  // Send the port that this process is listening on to the server.
+  SendMachPort(server_port.get(), client_port, MACH_MSG_TYPE_MAKE_SEND);
+  return client_port;
+}
+
+// The number of active names in the current task's port name space.
+mach_msg_type_number_t GetActiveNameCount() {
+  mach_port_name_array_t name_array;
+  mach_msg_type_number_t names_count;
+  mach_port_type_array_t type_array;
+  mach_msg_type_number_t types_count;
+  kern_return_t kr = mach_port_names(mach_task_self(), &name_array,
+                                     &names_count, &type_array, &types_count);
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "GetActiveNameCount";
+  return names_count;
+}
+
+}  // namespace
+
+class SharedMemoryMacMultiProcessTest : public MultiProcessTest {
+ public:
+  SharedMemoryMacMultiProcessTest() {}
+
+  CommandLine MakeCmdLine(const std::string& procname) override {
+    CommandLine command_line = MultiProcessTest::MakeCmdLine(procname);
+    // Pass the service name to the child process.
+    command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
+    return command_line;
+  }
+
+  void SetUpChild(const std::string& name) {
+    // Make a random service name so that this test doesn't conflict with other
+    // similar tests.
+    service_name_ = CreateRandomServiceName();
+    server_port_.reset(BecomeMachServer(service_name_.c_str()));
+    child_process_ = SpawnChild(name);
+    client_port_.reset(ReceiveMachPort(server_port_.get()));
+  }
+
+  static const int s_memory_size = 99999;
+
+ protected:
+  std::string service_name_;
+
+  // A port on which the main process listens for mach messages from the child
+  // process.
+  mac::ScopedMachReceiveRight server_port_;
+
+  // A port on which the child process listens for mach messages from the main
+  // process.
+  mac::ScopedMachSendRight client_port_;
+
+  base::Process child_process_;
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryMacMultiProcessTest);
+};
+
+// Tests that content written to shared memory in the server process can be read
+// by the child process.
+TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) {
+  // Mach-based SharedMemory isn't support on OSX 10.6.
+  if (mac::IsOSSnowLeopard())
+    return;
+
+  SetUpChild("MachBasedSharedMemoryClient");
+
+  scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
+
+  // Send the underlying memory object to the client process.
+  SendMachPort(client_port_.get(), shared_memory->handle().GetMemoryObject(),
+               MACH_MSG_TYPE_COPY_SEND);
+  int rv = -1;
+  ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
+      TestTimeouts::action_timeout(), &rv));
+  EXPECT_EQ(0, rv);
+}
+
+MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) {
+  mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp());
+  // The next mach port should be for a memory object.
+  mach_port_t memory_object = ReceiveMachPort(client_port.get());
+  SharedMemoryHandle shm(memory_object,
+                         SharedMemoryMacMultiProcessTest::s_memory_size,
+                         GetCurrentProcId());
+  SharedMemory shared_memory(shm, false);
+  shared_memory.Map(SharedMemoryMacMultiProcessTest::s_memory_size);
+  const char* start = static_cast<const char*>(shared_memory.memory());
+  for (int i = 0; i < SharedMemoryMacMultiProcessTest::s_memory_size; ++i) {
+    DCHECK_EQ(start[i], 'a');
+  }
+  return 0;
+}
+
+// Tests that mapping shared memory with an offset works correctly.
+TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) {
+  // Mach-based SharedMemory isn't support on OSX 10.6.
+  if (mac::IsOSSnowLeopard())
+    return;
+
+  SetUpChild("MachBasedSharedMemoryWithOffsetClient");
+
+  SharedMemoryHandle shm(s_memory_size);
+  ASSERT_TRUE(shm.IsValid());
+  SharedMemory shared_memory(shm, false);
+  shared_memory.Map(s_memory_size);
+
+  size_t page_size = SysInfo::VMAllocationGranularity();
+  char* start = static_cast<char*>(shared_memory.memory());
+  memset(start, 'a', page_size);
+  memset(start + page_size, 'b', page_size);
+  memset(start + 2 * page_size, 'c', page_size);
+
+  // Send the underlying memory object to the client process.
+  SendMachPort(
+      client_port_.get(), shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND);
+  int rv = -1;
+  ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
+      TestTimeouts::action_timeout(), &rv));
+  EXPECT_EQ(0, rv);
+}
+
+MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryWithOffsetClient) {
+  mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp());
+  // The next mach port should be for a memory object.
+  mach_port_t memory_object = ReceiveMachPort(client_port.get());
+  SharedMemoryHandle shm(memory_object,
+                         SharedMemoryMacMultiProcessTest::s_memory_size,
+                         GetCurrentProcId());
+  SharedMemory shared_memory(shm, false);
+  size_t page_size = SysInfo::VMAllocationGranularity();
+  shared_memory.MapAt(page_size, 2 * page_size);
+  const char* start = static_cast<const char*>(shared_memory.memory());
+  for (size_t i = 0; i < page_size; ++i) {
+    DCHECK_EQ(start[i], 'b');
+  }
+  for (size_t i = page_size; i < 2 * page_size; ++i) {
+    DCHECK_EQ(start[i], 'c');
+  }
+  return 0;
+}
+
+// Tests that duplication and closing has the right effect on Mach reference
+// counts.
+TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) {
+  // Mach-based SharedMemory isn't support on OSX 10.6.
+  if (mac::IsOSSnowLeopard())
+    return;
+
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  // Making a new SharedMemoryHandle increments the name count.
+  SharedMemoryHandle shm(s_memory_size);
+  ASSERT_TRUE(shm.IsValid());
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Duplicating the SharedMemoryHandle increments the ref count, but doesn't
+  // make a new name.
+  shm.Duplicate();
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Closing the SharedMemoryHandle decrements the ref count. The first time has
+  // no effect.
+  shm.Close();
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Closing the SharedMemoryHandle decrements the ref count. The second time
+  // destroys the port.
+  shm.Close();
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+// Tests that Mach shared memory can be mapped and unmapped.
+TEST_F(SharedMemoryMacMultiProcessTest, MachUnmapMap) {
+  // Mach-based SharedMemory isn't support on OSX 10.6.
+  if (mac::IsOSSnowLeopard())
+    return;
+
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  scoped_ptr<SharedMemory> shared_memory = CreateSharedMemory(s_memory_size);
+  ASSERT_TRUE(shared_memory->Unmap());
+  ASSERT_TRUE(shared_memory->Map(s_memory_size));
+  shared_memory.reset();
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+// Tests that passing a SharedMemoryHandle to a SharedMemory object also passes
+// ownership, and that destroying the SharedMemory closes the SharedMemoryHandle
+// as well.
+TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) {
+  // Mach-based SharedMemory isn't support on OSX 10.6.
+  if (mac::IsOSSnowLeopard())
+    return;
+
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  // Making a new SharedMemoryHandle increments the name count.
+  SharedMemoryHandle shm(s_memory_size);
+  ASSERT_TRUE(shm.IsValid());
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Name count doesn't change when mapping the memory.
+  scoped_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false));
+  shared_memory->Map(s_memory_size);
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Destroying the SharedMemory object frees the resource.
+  shared_memory.reset();
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+// Tests that the read-only flag works.
+TEST_F(SharedMemoryMacMultiProcessTest, MachReadOnly) {
+  // Mach-based SharedMemory isn't support on OSX 10.6.
+  if (mac::IsOSSnowLeopard())
+    return;
+
+  scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
+
+  SharedMemoryHandle shm2 = shared_memory->handle().Duplicate();
+  ASSERT_TRUE(shm2.IsValid());
+  SharedMemory shared_memory2(shm2, true);
+  shared_memory2.Map(s_memory_size);
+  ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
+}
+
+// Tests that the method ShareToProcess() works.
+TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcess) {
+  // Mach-based SharedMemory isn't support on OSX 10.6.
+  if (mac::IsOSSnowLeopard())
+    return;
+
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  {
+    scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
+
+    SharedMemoryHandle shm2;
+    ASSERT_TRUE(shared_memory->ShareToProcess(GetCurrentProcId(), &shm2));
+    ASSERT_TRUE(shm2.IsValid());
+    SharedMemory shared_memory2(shm2, true);
+    shared_memory2.Map(s_memory_size);
+
+    ASSERT_EQ(0, memcmp(shared_memory->memory(), shared_memory2.memory(),
+                        s_memory_size));
+  }
+
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+// Tests that the method ShareReadOnlyToProcess() creates a memory object that
+// is read only.
+TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonly) {
+  // Mach-based SharedMemory isn't support on OSX 10.6.
+  if (mac::IsOSSnowLeopard())
+    return;
+
+  scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
+
+  // Check the protection levels.
+  int current_prot, max_prot;
+  ASSERT_TRUE(GetProtections(shared_memory->memory(),
+                             shared_memory->mapped_size(), &current_prot,
+                             &max_prot));
+  ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, current_prot);
+  ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, max_prot);
+
+  // Make a new memory object.
+  SharedMemoryHandle shm2;
+  ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
+  ASSERT_TRUE(shm2.IsValid());
+
+  // Mapping with |readonly| set to |false| should fail.
+  SharedMemory shared_memory2(shm2, false);
+  shared_memory2.Map(s_memory_size);
+  ASSERT_EQ(nullptr, shared_memory2.memory());
+
+  // Now trying mapping with |readonly| set to |true|.
+  SharedMemory shared_memory3(shm2.Duplicate(), true);
+  shared_memory3.Map(s_memory_size);
+  ASSERT_NE(nullptr, shared_memory3.memory());
+
+  // Check the protection levels.
+  ASSERT_TRUE(GetProtections(shared_memory3.memory(),
+                             shared_memory3.mapped_size(), &current_prot,
+                             &max_prot));
+  ASSERT_EQ(VM_PROT_READ, current_prot);
+  ASSERT_EQ(VM_PROT_READ, max_prot);
+
+  // The memory should still be readonly, since the underlying memory object
+  // is readonly.
+  ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
+}
+
+// Tests that the method ShareReadOnlyToProcess() doesn't leak.
+TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonlyLeak) {
+  // Mach-based SharedMemory isn't support on OSX 10.6.
+  if (mac::IsOSSnowLeopard())
+    return;
+
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  {
+    scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
+
+    SharedMemoryHandle shm2;
+    ASSERT_TRUE(
+        shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
+    ASSERT_TRUE(shm2.IsValid());
+
+    // Intentionally map with |readonly| set to |false|.
+    SharedMemory shared_memory2(shm2, false);
+    shared_memory2.Map(s_memory_size);
+  }
+
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+}  //  namespace base
diff --git a/base/memory/shared_memory_nacl.cc b/base/memory/shared_memory_nacl.cc
index 8435b2b..7221ded 100644
--- a/base/memory/shared_memory_nacl.cc
+++ b/base/memory/shared_memory_nacl.cc
@@ -16,28 +16,33 @@
 
 namespace base {
 
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+    : name_deprecated(nullptr),
+      open_existing_deprecated(false),
+      size(0),
+      executable(false),
+      share_read_only(false) {}
+
 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)
+SharedMemory::SharedMemory(const 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,
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
+                           bool read_only,
                            ProcessHandle process)
     : mapped_file_(handle.fd),
-      inode_(0),
       mapped_size_(0),
       memory_(NULL),
       read_only_(read_only),
@@ -67,6 +72,15 @@
     DPLOG(ERROR) << "close";
 }
 
+// static
+SharedMemoryHandle SharedMemory::DuplicateHandle(
+    const SharedMemoryHandle& handle) {
+  int duped_handle = HANDLE_EINTR(dup(handle.fd));
+  if (duped_handle < 0)
+    return base::SharedMemory::NULLHandle();
+  return base::FileDescriptor(duped_handle, true);
+}
+
 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
   // Untrusted code can't create descriptors or handles.
   return false;
@@ -133,14 +147,6 @@
   }
 }
 
-void SharedMemory::LockDeprecated() {
-  NOTIMPLEMENTED();
-}
-
-void SharedMemory::UnlockDeprecated() {
-  NOTIMPLEMENTED();
-}
-
 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
                                         SharedMemoryHandle *new_handle,
                                         bool close_self,
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
index d6c290f..28c103f 100644
--- a/base/memory/shared_memory_posix.cc
+++ b/base/memory/shared_memory_posix.cc
@@ -8,24 +8,17 @@
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <sys/types.h>
 #include <unistd.h>
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/safe_strerror.h"
 #include "base/process/process_metrics.h"
 #include "base/profiler/scoped_tracker.h"
-#include "base/safe_strerror_posix.h"
+#include "base/scoped_generic.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread_restrictions.h"
-
-#if defined(OS_MACOSX)
-#include "base/mac/foundation_util.h"
-#endif  // OS_MACOSX
 
 #if defined(OS_ANDROID)
 #include "base/os_compat_android.h"
@@ -36,41 +29,105 @@
 
 namespace {
 
-LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER;
+struct ScopedPathUnlinkerTraits {
+  static FilePath* InvalidValue() { return nullptr; }
 
+  static void Free(FilePath* path) {
+    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+    // is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "466437 SharedMemory::Create::Unlink"));
+    if (unlink(path->value().c_str()))
+      PLOG(WARNING) << "unlink";
+  }
+};
+
+// Unlinks the FilePath when the object is destroyed.
+typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
+
+#if !defined(OS_ANDROID)
+// Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
+// with the fdopened FILE. |readonly_fd| is populated with the opened fd if
+// options.share_read_only is true. |path| is populated with the location of
+// the file before it was unlinked.
+// Returns false if there's an unhandled failure.
+bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
+                                 ScopedFILE* fp,
+                                 ScopedFD* readonly_fd,
+                                 FilePath* path) {
+  // It doesn't make sense to have a open-existing private piece of shmem
+  DCHECK(!options.open_existing_deprecated);
+  // Q: Why not use the shm_open() etc. APIs?
+  // A: Because they're limited to 4mb on OS X.  FFFFFFFUUUUUUUUUUU
+  FilePath directory;
+  ScopedPathUnlinker path_unlinker;
+  if (GetShmemTempDir(options.executable, &directory)) {
+    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+    // is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "466437 SharedMemory::Create::OpenTemporaryFile"));
+    fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path));
+
+    // Deleting the file prevents anyone else from mapping it in (making it
+    // private), and prevents the need for cleanup (once the last fd is
+    // closed, it is truly freed).
+    if (*fp)
+      path_unlinker.reset(path);
+  }
+
+  if (*fp) {
+    if (options.share_read_only) {
+      // TODO(erikchen): Remove ScopedTracker below once
+      // http://crbug.com/466437 is fixed.
+      tracked_objects::ScopedTracker tracking_profile(
+          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+              "466437 SharedMemory::Create::OpenReadonly"));
+      // Also open as readonly so that we can ShareReadOnlyToProcess.
+      readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
+      if (!readonly_fd->is_valid()) {
+        DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
+        fp->reset();
+        return false;
+      }
+    }
+  }
+  return true;
 }
+#endif  // !defined(OS_ANDROID)
+}
+
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+    : name_deprecated(nullptr),
+      open_existing_deprecated(false),
+      size(0),
+      executable(false),
+      share_read_only(false) {}
 
 SharedMemory::SharedMemory()
     : mapped_file_(-1),
       readonly_mapped_file_(-1),
-      inode_(0),
       mapped_size_(0),
       memory_(NULL),
       read_only_(false),
       requested_size_(0) {
 }
 
-SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+SharedMemory::SharedMemory(const 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,
+SharedMemory::SharedMemory(const 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),
@@ -98,7 +155,7 @@
 // static
 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
   DCHECK_GE(handle.fd, 0);
-  if (close(handle.fd) < 0)
+  if (IGNORE_EINTR(close(handle.fd)) < 0)
     DPLOG(ERROR) << "close";
 }
 
@@ -107,11 +164,39 @@
   return base::GetMaxFds();
 }
 
+// static
+SharedMemoryHandle SharedMemory::DuplicateHandle(
+    const SharedMemoryHandle& handle) {
+  int duped_handle = HANDLE_EINTR(dup(handle.fd));
+  if (duped_handle < 0)
+    return base::SharedMemory::NULLHandle();
+  return base::FileDescriptor(duped_handle, true);
+}
+
+// static
+int SharedMemory::GetFdFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle) {
+  return handle.fd;
+}
+
 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
   return CreateAnonymous(size) && Map(size);
 }
 
 #if !defined(OS_ANDROID)
+// static
+bool SharedMemory::GetSizeFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle,
+    size_t* size) {
+  struct stat st;
+  if (fstat(handle.fd, &st) != 0)
+    return false;
+  if (st.st_size < 0)
+    return false;
+  *size = st.st_size;
+  return true;
+}
+
 // Chromium mostly only uses the unique/private shmem as specified by
 // "name == L"". The exception is in the StatsTable.
 // TODO(jrg): there is no way to "clean up" all unused named shmem if
@@ -141,47 +226,10 @@
 
   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";
-    }
+    bool result =
+        CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
+    if (!result)
+      return false;
   } else {
     if (!FilePathForMemoryName(*options.name_deprecated, &path))
       return false;
@@ -251,7 +299,6 @@
     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) {
@@ -261,13 +308,10 @@
                    << "/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());
+  return PrepareMapFile(std::move(fp), std::move(readonly_fd));
 }
 
 // Our current implementation of shmem is with mmap()ing of files.
@@ -299,7 +343,7 @@
     DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
     return false;
   }
-  return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+  return PrepareMapFile(std::move(fp), std::move(readonly_fd));
 }
 #endif  // !defined(OS_ANDROID)
 
@@ -356,27 +400,17 @@
 
 void SharedMemory::Close() {
   if (mapped_file_ > 0) {
-    if (close(mapped_file_) < 0)
+    if (IGNORE_EINTR(close(mapped_file_)) < 0)
       PLOG(ERROR) << "close";
     mapped_file_ = -1;
   }
   if (readonly_mapped_file_ > 0) {
-    if (close(readonly_mapped_file_) < 0)
+    if (IGNORE_EINTR(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_);
@@ -402,7 +436,7 @@
     }
   }
 
-  mapped_file_ = dup(fileno(fp.get()));
+  mapped_file_ = HANDLE_EINTR(dup(fileno(fp.get())));
   if (mapped_file_ == -1) {
     if (errno == EMFILE) {
       LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
@@ -411,7 +445,6 @@
       NOTREACHED() << "Call to dup failed, errno=" << errno;
     }
   }
-  inode_ = st.st_ino;
   readonly_mapped_file_ = readonly_fd.release();
 
   return true;
@@ -431,39 +464,16 @@
   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,
@@ -481,8 +491,12 @@
       break;
   }
 
-  const int new_fd = dup(handle_to_dup);
+  const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
   if (new_fd < 0) {
+    if (close_self) {
+      Unmap();
+      Close();
+    }
     DPLOG(ERROR) << "dup() failed.";
     return false;
   }
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc
index 6fe5706..561c065 100644
--- a/base/memory/shared_memory_unittest.cc
+++ b/base/memory/shared_memory_unittest.cc
@@ -2,6 +2,7 @@
 // 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 "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/shared_memory.h"
@@ -15,10 +16,6 @@
 #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>
@@ -32,15 +29,11 @@
 #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 {
 
+#if !defined(OS_MACOSX)
 // Each thread will open the shared memory.  Each thread will take a different 4
 // byte int pointer, and keep changing it, with some small pauses in between.
 // Verify that each thread's value in the shared memory is always correct.
@@ -56,21 +49,18 @@
 
   // 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_;
+    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));
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
       EXPECT_EQ(*ptr, idx);
     }
     // Reset back to 0 for the next test that uses the same name.
@@ -89,62 +79,13 @@
 
 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
+#endif  // !defined(OS_MACOSX)
 
 }  // namespace
 
-// Android doesn't support SharedMemory::Open/Delete/
+// Android/Mac doesn't support SharedMemory::Open/Delete/
 // CreateNamedDeprecated(openExisting=true)
-#if !defined(OS_ANDROID)
+#if !defined(OS_ANDROID) && !defined(OS_MACOSX)
 TEST(SharedMemoryTest, OpenClose) {
   const uint32 kDataSize = 1024;
   std::string test_name = "SharedMemoryOpenCloseTest";
@@ -179,8 +120,8 @@
 
   // 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;
+  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');
 
@@ -218,7 +159,7 @@
 
   // The mapped memory1 shouldn't exceed rounding for allocation granularity.
   EXPECT_LT(memory1.mapped_size(),
-            kDataSize + base::SysInfo::VMAllocationGranularity());
+            kDataSize + SysInfo::VMAllocationGranularity());
 
   memset(memory1.memory(), 'G', kDataSize);
 
@@ -243,11 +184,11 @@
 
   // The mapped memory2 shouldn't exceed rounding for allocation granularity.
   EXPECT_LT(memory2.mapped_size(),
-            kDataSize2 + base::SysInfo::VMAllocationGranularity());
+            kDataSize2 + SysInfo::VMAllocationGranularity());
 
   // Verify that opening memory2 didn't truncate or delete memory 1.
-  char *start_ptr = static_cast<char *>(memory2.memory());
-  char *end_ptr = start_ptr + kDataSize;
+  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');
   }
@@ -258,7 +199,7 @@
   rv = memory1.Delete(test_name);
   EXPECT_TRUE(rv);
 }
-#endif
+#endif  // !defined(OS_ANDROID) && !defined(OS_MACOSX)
 
 // Check that memory is still mapped after its closed.
 TEST(SharedMemoryTest, CloseNoUnmap) {
@@ -283,9 +224,12 @@
   EXPECT_EQ(nullptr, memory.memory());
 }
 
+#if !defined(OS_MACOSX)
 // Create a set of N threads to each open a shared memory segment and write to
 // it. Verify that they are always reading/writing consistent data.
 TEST(SharedMemoryTest, MultipleThreads) {
+  const int kNumThreads = 5;
+
   MultipleThreadMain::CleanUp();
   // On POSIX we have a problem when 2 threads try to create the shmem
   // (a file) at exactly the same time, since create both creates the
@@ -319,33 +263,6 @@
   }
   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
@@ -365,7 +282,7 @@
   for (i = 0; i < count; i++) {
     rv = memories[i].CreateAndMapAnonymous(kDataSize);
     EXPECT_TRUE(rv);
-    int *ptr = static_cast<int*>(memories[i].memory());
+    int* ptr = static_cast<int*>(memories[i].memory());
     EXPECT_TRUE(ptr);
     pointers[i] = ptr;
   }
@@ -399,6 +316,10 @@
   SharedMemoryCreateOptions options;
   options.size = contents.size();
   options.share_read_only = true;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+  options.type = SharedMemoryHandle::POSIX;
+#endif
   ASSERT_TRUE(writable_shmem.Create(options));
   ASSERT_TRUE(writable_shmem.Map(options.size));
   memcpy(writable_shmem.memory(), contents.data(), contents.size());
@@ -437,12 +358,13 @@
   // http://crbug.com/320865
   (void)handle;
 #elif defined(OS_POSIX)
-  EXPECT_EQ(O_RDONLY, fcntl(handle.fd, F_GETFL) & O_ACCMODE)
+  int handle_fd = SharedMemory::GetFdFromSharedMemoryHandle(handle);
+  EXPECT_EQ(O_RDONLY, fcntl(handle_fd, F_GETFL) & O_ACCMODE)
       << "The descriptor itself should be read-only.";
 
   errno = 0;
-  void* writable = mmap(
-      NULL, contents.size(), PROT_READ | PROT_WRITE, MAP_SHARED, handle.fd, 0);
+  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.";
@@ -451,32 +373,24 @@
     EXPECT_EQ(0, munmap(writable, readonly_shmem.mapped_size()));
 
 #elif defined(OS_WIN)
-  EXPECT_EQ(NULL, MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, 0))
+  EXPECT_EQ(NULL, MapViewOfFile(handle.GetHandle(), FILE_MAP_WRITE, 0, 0, 0))
       << "Shouldn't be able to map memory writable.";
 
   HANDLE temp_handle;
-  BOOL rv = ::DuplicateHandle(GetCurrentProcess(),
-                              handle,
-                              GetCurrentProcess(),
-                              &temp_handle,
-                              FILE_MAP_ALL_ACCESS,
-                              false,
-                              0);
+  BOOL rv = ::DuplicateHandle(GetCurrentProcess(), handle.GetHandle(),
+                              GetCurrentProcess(), &temp_handle,
+                              FILE_MAP_ALL_ACCESS, false, 0);
   EXPECT_EQ(FALSE, rv)
       << "Shouldn't be able to duplicate the handle into a writable one.";
   if (rv)
-    base::win::ScopedHandle writable_handle(temp_handle);
-  rv = ::DuplicateHandle(GetCurrentProcess(),
-                         handle,
-                         GetCurrentProcess(),
-                         &temp_handle,
-                         FILE_MAP_READ,
-                         false,
-                         0);
+    win::ScopedHandle writable_handle(temp_handle);
+  rv = ::DuplicateHandle(GetCurrentProcess(), handle.GetHandle(),
+                         GetCurrentProcess(), &temp_handle, FILE_MAP_READ,
+                         false, 0);
   EXPECT_EQ(TRUE, rv)
       << "Should be able to duplicate the handle into a readable one.";
   if (rv)
-    base::win::ScopedHandle writable_handle(temp_handle);
+    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)
@@ -499,6 +413,7 @@
       contents,
       StringPiece(static_cast<const char*>(shared.memory()), contents.size()));
 
+  shared_handle = SharedMemoryHandle();
   ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
   SharedMemory readonly(shared_handle, /*readonly=*/true);
 
@@ -558,6 +473,10 @@
   SharedMemoryCreateOptions options;
   options.size = kTestSize;
   options.executable = true;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+  options.type = SharedMemoryHandle::POSIX;
+#endif
 
   EXPECT_TRUE(shared_memory.Create(options));
   EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size()));
@@ -591,12 +510,17 @@
   SharedMemory shared_memory;
   SharedMemoryCreateOptions options;
   options.size = kTestSize;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+  options.type = SharedMemoryHandle::POSIX;
+#endif
   // 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;
+  int shm_fd =
+      SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle());
   struct stat shm_stat;
   EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
   // Neither the group, nor others should be able to read the shared memory
@@ -607,24 +531,24 @@
 
 // Create a shared memory object, check its permissions.
 TEST(SharedMemoryTest, FilePermissionsNamed) {
-  const uint32 kTestSize = 1 << 8;
+  const uint32_t 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;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+  options.type = SharedMemoryHandle::POSIX;
+#endif
+
   // 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;
+  int fd = SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle());
   struct stat shm_stat;
-  EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
+  EXPECT_EQ(0, fstat(fd, &shm_stat));
   // Neither the group, nor others should have been able to open the shared
   // memory file while its name existed.
   EXPECT_FALSE(shm_stat.st_mode & S_IRWXO);
@@ -647,13 +571,14 @@
   shared_memory.Close();
 }
 
-#if !defined(OS_IOS)  // iOS does not allow multiple processes.
-
+// iOS does not allow multiple processes.
+// Android ashmem does not support named shared memory.
+// Mac SharedMemory does not support named shared memory. crbug.com/345734
+#if !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
 // On POSIX it is especially important we test shmem across processes,
 // not just across threads.  But the test is enabled on all platforms.
 class SharedMemoryProcessTest : public MultiProcessTest {
  public:
-
   static void CleanUp() {
     SharedMemory memory;
     memory.Delete(s_test_name_);
@@ -661,63 +586,69 @@
 
   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);
+    bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_);
     EXPECT_TRUE(rv);
     if (rv != true)
       errors++;
-    rv = memory.Map(kDataSize);
+    rv = memory.Map(s_data_size_);
     EXPECT_TRUE(rv);
     if (rv != true)
       errors++;
-    int *ptr = static_cast<int*>(memory.memory());
+    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();
-    }
-
+    // This runs concurrently in multiple processes. Writes need to be atomic.
+    subtle::Barrier_AtomicIncrement(ptr, 1);
     memory.Close();
     return errors;
   }
 
- private:
   static const char* const s_test_name_;
+  static const uint32 s_data_size_;
 };
 
 const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
+const uint32 SharedMemoryProcessTest::s_data_size_ = 1024;
 
-TEST_F(SharedMemoryProcessTest, Tasks) {
+TEST_F(SharedMemoryProcessTest, SharedMemoryAcrossProcesses) {
+  const int kNumTasks = 5;
+
   SharedMemoryProcessTest::CleanUp();
 
+  // Create a shared memory region. Set the first word to 0.
+  SharedMemory memory;
+  bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_);
+  ASSERT_TRUE(rv);
+  rv = memory.Map(s_data_size_);
+  ASSERT_TRUE(rv);
+  int* ptr = static_cast<int*>(memory.memory());
+  *ptr = 0;
+
+  // Start |kNumTasks| processes, each of which atomically increments the first
+  // word by 1.
   Process processes[kNumTasks];
   for (int index = 0; index < kNumTasks; ++index) {
     processes[index] = SpawnChild("SharedMemoryTestMain");
     ASSERT_TRUE(processes[index].IsValid());
   }
 
+  // Check that each process exited correctly.
   int exit_code = 0;
   for (int index = 0; index < kNumTasks; ++index) {
     EXPECT_TRUE(processes[index].WaitForExit(&exit_code));
     EXPECT_EQ(0, exit_code);
   }
 
+  // Check that the shared memory region reflects |kNumTasks| increments.
+  ASSERT_EQ(kNumTasks, *ptr);
+
+  memory.Close();
   SharedMemoryProcessTest::CleanUp();
 }
 
 MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
   return SharedMemoryProcessTest::TaskTestMain();
 }
-
-#endif  // !OS_IOS
+#endif  // !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
 
 }  // namespace base
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc
index 7e0cf0b..fd8d2fd 100644
--- a/base/memory/shared_memory_win.cc
+++ b/base/memory/shared_memory_win.cc
@@ -27,70 +27,70 @@
 
 namespace base {
 
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+    : name_deprecated(nullptr),
+      open_existing_deprecated(false),
+      size(0),
+      executable(false),
+      share_read_only(false) {}
+
 SharedMemory::SharedMemory()
     : mapped_file_(NULL),
+      mapped_size_(0),
       memory_(NULL),
       read_only_(false),
-      mapped_size_(0),
-      requested_size_(0),
-      lock_(NULL) {
+      requested_size_(0) {
 }
 
 SharedMemory::SharedMemory(const std::wstring& name)
-    : mapped_file_(NULL),
+    : name_(name),
+      mapped_file_(NULL),
+      mapped_size_(0),
       memory_(NULL),
       read_only_(false),
-      requested_size_(0),
-      mapped_size_(0),
-      lock_(NULL),
-      name_(name) {
+      requested_size_(0) {
 }
 
-SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
-    : mapped_file_(handle),
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
+    : mapped_file_(handle.GetHandle()),
+      mapped_size_(0),
       memory_(NULL),
       read_only_(read_only),
-      requested_size_(0),
-      mapped_size_(0),
-      lock_(NULL) {
+      requested_size_(0) {
+  DCHECK(!handle.IsValid() || handle.BelongsToCurrentProcess());
 }
 
-SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
+                           bool read_only,
                            ProcessHandle process)
     : mapped_file_(NULL),
+      mapped_size_(0),
       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);
+      requested_size_(0) {
+  ::DuplicateHandle(
+      process, handle.GetHandle(), 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;
+  return handle.IsValid();
 }
 
 // static
 SharedMemoryHandle SharedMemory::NULLHandle() {
-  return NULL;
+  return SharedMemoryHandle();
 }
 
 // static
 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
-  DCHECK(handle != NULL);
-  ::CloseHandle(handle);
+  handle.Close();
 }
 
 // static
@@ -100,6 +100,20 @@
   return static_cast<size_t>(1 << 23);
 }
 
+// static
+SharedMemoryHandle SharedMemory::DuplicateHandle(
+    const SharedMemoryHandle& handle) {
+  DCHECK(handle.BelongsToCurrentProcess());
+  HANDLE duped_handle;
+  ProcessHandle process = GetCurrentProcess();
+  BOOL success =
+      ::DuplicateHandle(process, handle.GetHandle(), process, &duped_handle, 0,
+                        FALSE, DUPLICATE_SAME_ACCESS);
+  if (success)
+    return SharedMemoryHandle(duped_handle, GetCurrentProcId());
+  return SharedMemoryHandle();
+}
+
 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
   return CreateAnonymous(size) && Map(size);
 }
@@ -139,7 +153,7 @@
     // 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",
+    name_ = StringPrintf(L"CrSharedMem_%016llx%016llx%016llx%016llx",
                          rand_values[0], rand_values[1],
                          rand_values[2], rand_values[3]);
   }
@@ -223,7 +237,7 @@
                                         SharedMemoryHandle* new_handle,
                                         bool close_self,
                                         ShareMode share_mode) {
-  *new_handle = 0;
+  *new_handle = SharedMemoryHandle();
   DWORD access = FILE_MAP_READ;
   DWORD options = 0;
   HANDLE mapped_file = mapped_file_;
@@ -238,47 +252,28 @@
   }
 
   if (process == GetCurrentProcess() && close_self) {
-    *new_handle = mapped_file;
+    *new_handle = SharedMemoryHandle(mapped_file, base::GetCurrentProcId());
     return true;
   }
 
-  if (!DuplicateHandle(GetCurrentProcess(), mapped_file, process,
-      &result, access, FALSE, options))
+  if (!::DuplicateHandle(GetCurrentProcess(), mapped_file, process, &result,
+                         access, FALSE, options)) {
     return false;
-  *new_handle = result;
+  }
+  *new_handle = SharedMemoryHandle(result, base::GetProcId(process));
   return true;
 }
 
 
 void SharedMemory::Close() {
   if (mapped_file_ != NULL) {
-    CloseHandle(mapped_file_);
+    ::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_;
+  return SharedMemoryHandle(mapped_file_, base::GetCurrentProcId());
 }
 
 }  // namespace base
diff --git a/base/memory/singleton.h b/base/memory/singleton.h
index e50bdc0..7319699 100644
--- a/base/memory/singleton.h
+++ b/base/memory/singleton.h
@@ -36,10 +36,10 @@
 // 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
+class DeleteTraceLogForTesting;
 
-// TODO(joth): Move more of this file into namespace base
+}  // namespace internal
+
 
 // Default traits for Singleton<Type>. Calls operator new and operator delete on
 // the object. Registers automatic deletion at process exit.
@@ -110,7 +110,7 @@
   // 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))
+    if (subtle::NoBarrier_AtomicExchange(&dead_, 1))
       return NULL;
 
     return new(buffer_.void_data()) Type();
@@ -125,20 +125,19 @@
   static const bool kAllowedToAccessOnNonjoinableThread = true;
 
   // Exposed for unittesting.
-  static void Resurrect() {
-    base::subtle::NoBarrier_Store(&dead_, 0);
-  }
+  static void Resurrect() { subtle::NoBarrier_Store(&dead_, 0); }
 
  private:
-  static base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
+  static AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
   // Signal the object was already deleted, so it is not revived.
-  static base::subtle::Atomic32 dead_;
+  static subtle::Atomic32 dead_;
 };
 
-template <typename Type> base::AlignedMemory<sizeof(Type), ALIGNOF(Type)>
+template <typename Type>
+AlignedMemory<sizeof(Type), ALIGNOF(Type)>
     StaticMemorySingletonTraits<Type>::buffer_;
-template <typename Type> base::subtle::Atomic32
-    StaticMemorySingletonTraits<Type>::dead_ = 0;
+template <typename Type>
+subtle::Atomic32 StaticMemorySingletonTraits<Type>::dead_ = 0;
 
 // The Singleton<Type, Traits, DifferentiatingType> class manages a single
 // instance of Type which will be created on first use and will be destroyed at
@@ -190,7 +189,7 @@
 //   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
+// process exit. More precisely it uses AtExitManager which requires an
 // object of this type to be instantiated. AtExitManager mimics the semantics
 // of atexit() such as LIFO order but under Windows is safer to call. For more
 // information see at_exit.h.
@@ -209,6 +208,7 @@
 // (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>
@@ -219,7 +219,7 @@
   friend Type* Type::GetInstance();
 
   // Allow TraceLog tests to test tracing after OnExit.
-  friend class DeleteTraceLogForTesting;
+  friend class internal::DeleteTraceLogForTesting;
 
   // This class is safe to be constructed and copy-constructed since it has no
   // member.
@@ -229,36 +229,36 @@
 #ifndef NDEBUG
     // Avoid making TLS lookup on release builds.
     if (!Traits::kAllowedToAccessOnNonjoinableThread)
-      base::ThreadRestrictions::AssertSingletonAllowed();
+      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) {
+    subtle::AtomicWord value = subtle::Acquire_Load(&instance_);
+    if (value != 0 && value != internal::kBeingCreatedMarker) {
       return reinterpret_cast<Type*>(value);
     }
 
     // Object isn't created yet, maybe we will get to create it, let's try...
-    if (base::subtle::Acquire_CompareAndSwap(
-          &instance_, 0, base::internal::kBeingCreatedMarker) == 0) {
+    if (subtle::Acquire_CompareAndSwap(&instance_, 0,
+                                       internal::kBeingCreatedMarker) == 0) {
       // instance_ was NULL and is now kBeingCreatedMarker.  Only one thread
       // will ever get here.  Threads might be spinning on us, and they will
       // stop right after we do this store.
       Type* newval = Traits::New();
 
       // Releases the visibility over instance_ to the readers.
-      base::subtle::Release_Store(
-          &instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
+      subtle::Release_Store(&instance_,
+                            reinterpret_cast<subtle::AtomicWord>(newval));
 
       if (newval != NULL && Traits::kRegisterAtExit)
-        base::AtExitManager::RegisterCallback(OnExit, NULL);
+        AtExitManager::RegisterCallback(OnExit, NULL);
 
       return newval;
     }
 
     // We hit a race. Wait for the other thread to complete it.
-    value = base::internal::WaitForInstance(&instance_);
+    value = internal::WaitForInstance(&instance_);
 
     return reinterpret_cast<Type*>(value);
   }
@@ -269,15 +269,15 @@
   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_)));
+    Traits::Delete(reinterpret_cast<Type*>(subtle::NoBarrier_Load(&instance_)));
     instance_ = 0;
   }
-  static base::subtle::AtomicWord instance_;
+  static subtle::AtomicWord instance_;
 };
 
 template <typename Type, typename Traits, typename DifferentiatingType>
-base::subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::
-    instance_ = 0;
+subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::instance_ = 0;
+
+}  // namespace base
 
 #endif  // BASE_MEMORY_SINGLETON_H_
diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc
index dbff007..28daf10 100644
--- a/base/memory/singleton_unittest.cc
+++ b/base/memory/singleton_unittest.cc
@@ -6,9 +6,11 @@
 #include "base/memory/singleton.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace base {
 namespace {
 
-COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
+static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true,
+              "object must be deleted on process exit");
 
 typedef void (*CallbackFunc)();
 
@@ -115,7 +117,7 @@
   ~AlignedTestSingleton() {}
   static AlignedTestSingleton* GetInstance() {
     return Singleton<AlignedTestSingleton,
-        StaticMemorySingletonTraits<AlignedTestSingleton> >::get();
+                     StaticMemorySingletonTraits<AlignedTestSingleton>>::get();
   }
 
   Type type_;
@@ -147,7 +149,6 @@
   return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
 }
 
-}  // namespace
 
 class SingletonTest : public testing::Test {
  public:
@@ -207,7 +208,7 @@
   CallbackFunc* static_singleton;
 
   {
-    base::ShadowingAtExitManager sem;
+    ShadowingAtExitManager sem;
     {
       singleton_int = SingletonInt();
     }
@@ -241,7 +242,7 @@
   EXPECT_EQ(NULL, GetStaticSingleton());
 
   {
-    base::ShadowingAtExitManager sem;
+    ShadowingAtExitManager sem;
     // Verifiy that the variables were reset.
     {
       singleton_int = SingletonInt();
@@ -285,3 +286,6 @@
   EXPECT_ALIGNED(align128, 128);
   EXPECT_ALIGNED(align4096, 4096);
 }
+
+}  // namespace
+}  // namespace base
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
index 8a43392..c62f29c 100644
--- a/base/memory/weak_ptr.h
+++ b/base/memory/weak_ptr.h
@@ -16,6 +16,7 @@
 //
 //  class Controller {
 //   public:
+//    Controller() : weak_factory_(this) {}
 //    void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
 //    void WorkComplete(const Result& result) { ... }
 //   private:
@@ -58,8 +59,13 @@
 // 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.
+// If all WeakPtr objects are destroyed or invalidated then the factory is
+// unbound from the SequencedTaskRunner/Thread. The WeakPtrFactory may then be
+// destroyed, or new WeakPtr objects may be used, from a different sequence.
+//
+// Thus, at least one WeakPtr object must exist and have been dereferenced on
+// the correct thread to enforce that other WeakPtr objects will enforce they
+// are used on the desired thread.
 
 #ifndef BASE_MEMORY_WEAK_PTR_H_
 #define BASE_MEMORY_WEAK_PTR_H_
@@ -155,8 +161,8 @@
   static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
     typedef
         is_convertible<Derived, internal::SupportsWeakPtrBase&> convertible;
-    COMPILE_ASSERT(convertible::value,
-                   AsWeakPtr_argument_inherits_from_SupportsWeakPtr);
+    static_assert(convertible::value,
+                  "AsWeakPtr argument must inherit from SupportsWeakPtr");
     return AsWeakPtrImpl<Derived>(t, *t);
   }
 
diff --git a/base/memory/weak_ptr_unittest.nc b/base/memory/weak_ptr_unittest.nc
index 2ab428d..8486ff9 100644
--- a/base/memory/weak_ptr_unittest.nc
+++ b/base/memory/weak_ptr_unittest.nc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
 #include "base/memory/weak_ptr.h"
 
 namespace base {
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index c1ce939..eab14e9 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -44,7 +44,8 @@
       message_loop_(message_loop),
       next_sequence_num_(0),
       message_loop_scheduled_(false),
-      always_schedule_work_(AlwaysNotifyPump(message_loop_->type())) {
+      always_schedule_work_(AlwaysNotifyPump(message_loop_->type())),
+      is_ready_for_scheduling_(false) {
 }
 
 bool IncomingTaskQueue::AddToIncomingQueue(
@@ -109,6 +110,15 @@
   message_loop_ = NULL;
 }
 
+void IncomingTaskQueue::StartScheduling() {
+  AutoLock lock(incoming_queue_lock_);
+  DCHECK(!is_ready_for_scheduling_);
+  DCHECK(!message_loop_scheduled_);
+  is_ready_for_scheduling_ = true;
+  if (!incoming_queue_.empty())
+    ScheduleWork();
+}
+
 IncomingTaskQueue::~IncomingTaskQueue() {
   // Verify that WillDestroyCurrentMessageLoop() has been called.
   DCHECK(!message_loop_);
@@ -137,7 +147,7 @@
   }
 
   // Initialize the sequence number. The sequence number is used for delayed
-  // tasks (to faciliate FIFO sorting when two tasks have the same
+  // tasks (to facilitate FIFO sorting when two tasks have the same
   // delayed_run_time value) and for identifying the task in about:tracing.
   pending_task->sequence_num = next_sequence_num_++;
 
@@ -148,19 +158,25 @@
   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;
+  if (is_ready_for_scheduling_ &&
+      (always_schedule_work_ || (!message_loop_scheduled_ && was_empty))) {
+    ScheduleWork();
   }
 
   return true;
 }
 
+void IncomingTaskQueue::ScheduleWork() {
+  DCHECK(is_ready_for_scheduling_);
+  // Wake up the message loop.
+  message_loop_->ScheduleWork();
+  // After we've scheduled the message loop, we do not need to do so again
+  // until we know it has processed all of the work in our queue and is
+  // waiting for more work again. The message loop will always attempt to
+  // reload from the incoming queue before waiting again so we clear this flag
+  // in ReloadWorkQueue().
+  message_loop_scheduled_ = true;
+}
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index 72e1f30..7dd1e82 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -53,6 +53,10 @@
   // Disconnects |this| from the parent message loop.
   void WillDestroyCurrentMessageLoop();
 
+  // This should be called when the message loop becomes ready for
+  // scheduling work.
+  void StartScheduling();
+
  private:
   friend class RefCountedThreadSafe<IncomingTaskQueue>;
   virtual ~IncomingTaskQueue();
@@ -66,6 +70,9 @@
   // does not retain |pending_task->task| beyond this function call.
   bool PostPendingTask(PendingTask* pending_task);
 
+  // Wakes up the message loop and schedules work.
+  void ScheduleWork();
+
   // Number of tasks that require high resolution timing. This value is kept
   // so that ReloadWorkQueue() completes in constant time.
   int high_res_task_count_;
@@ -92,6 +99,9 @@
   // if the incoming queue was not empty.
   const bool always_schedule_work_;
 
+  // False until StartScheduling() is called.
+  bool is_ready_for_scheduling_;
+
   DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue);
 };
 
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index eb0f968..a0c5f61 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -5,6 +5,7 @@
 #include "base/message_loop/message_loop.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
@@ -19,6 +20,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_local.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
 #include "base/tracked_objects.h"
 
 #if defined(OS_MACOSX)
@@ -43,7 +45,7 @@
 LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky lazy_tls_ptr =
     LAZY_INSTANCE_INITIALIZER;
 
-// Logical events for Histogram profiling. Run with -message-loop-histogrammer
+// 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)
@@ -55,9 +57,9 @@
 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,
+// constant) and creates a pair to initialize an array of pairs.  In this case,
 // our pair consists of the expressions value, and the "stringized" version
-// of the expression (i.e., the exrpression put in quotes).  For example, if
+// of the expression (i.e., the expression put in quotes).  For example, if
 // we have:
 //    #define FOO 2
 //    #define BAR 5
@@ -78,7 +80,7 @@
   VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
   VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
 
-  {-1, NULL}  // The list must be null terminated, per API to histogram.
+  {-1, NULL}  // The list must be null-terminated, per API to histogram.
 };
 #endif  // !defined(OS_NACL)
 
@@ -100,6 +102,10 @@
 }
 #endif  // !defined(OS_NACL_SFI)
 
+scoped_ptr<MessagePump> ReturnPump(scoped_ptr<MessagePump> pump) {
+  return pump;
+}
+
 }  // namespace
 
 //------------------------------------------------------------------------------
@@ -116,41 +122,19 @@
 //------------------------------------------------------------------------------
 
 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(type, MessagePumpFactoryCallback()) {
+  BindToCurrentThread();
 }
 
 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(TYPE_CUSTOM, Bind(&ReturnPump, Passed(&pump))) {
+  BindToCurrentThread();
 }
 
 MessageLoop::~MessageLoop() {
-  DCHECK_EQ(this, current());
+  // current() could be NULL if this message loop is destructed before it is
+  // bound to a thread.
+  DCHECK(current() == this || !current());
 
   // iOS just attaches to the loop, it doesn't Run it.
   // TODO(stuartmorgan): Consider wiring up a Detach().
@@ -188,7 +172,8 @@
   // Tell the incoming queue that we are dying.
   incoming_task_queue_->WillDestroyCurrentMessageLoop();
   incoming_task_queue_ = NULL;
-  message_loop_proxy_ = NULL;
+  unbound_task_runner_ = NULL;
+  task_runner_ = NULL;
 
   // OK, now make it so that no one can find us.
   lazy_tls_ptr.Pointer()->Set(NULL);
@@ -275,35 +260,37 @@
 void MessageLoop::PostTask(
     const tracked_objects::Location& from_here,
     const Closure& task) {
-  message_loop_proxy_->PostTask(from_here, task);
+  task_runner_->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);
+  task_runner_->PostDelayedTask(from_here, task, delay);
 }
 
 void MessageLoop::PostNonNestableTask(
     const tracked_objects::Location& from_here,
     const Closure& task) {
-  message_loop_proxy_->PostNonNestableTask(from_here, task);
+  task_runner_->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);
+  task_runner_->PostNonNestableDelayedTask(from_here, task, delay);
 }
 
 void MessageLoop::Run() {
+  DCHECK(pump_);
   RunLoop run_loop;
   run_loop.Run();
 }
 
 void MessageLoop::RunUntilIdle() {
+  DCHECK(pump_);
   RunLoop run_loop;
   run_loop.RunUntilIdle();
 }
@@ -376,22 +363,71 @@
 }
 
 bool MessageLoop::IsIdleForTesting() {
-  // We only check the imcoming queue|, since we don't want to lock the work
+  // We only check the incoming queue, since we don't want to lock the work
   // queue.
   return incoming_task_queue_->IsIdleForTesting();
 }
 
 //------------------------------------------------------------------------------
 
-void MessageLoop::Init() {
+// static
+scoped_ptr<MessageLoop> MessageLoop::CreateUnbound(
+    Type type, MessagePumpFactoryCallback pump_factory) {
+  return make_scoped_ptr(new MessageLoop(type, pump_factory));
+}
+
+MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory)
+    : type_(type),
+#if defined(OS_WIN)
+      pending_high_res_tasks_(0),
+      in_high_res_mode_(false),
+#endif
+      nestable_tasks_allowed_(true),
+#if defined(OS_WIN)
+      os_modal_loop_(false),
+#endif  // OS_WIN
+      pump_factory_(pump_factory),
+      message_histogram_(NULL),
+      run_loop_(NULL),
+      incoming_task_queue_(new internal::IncomingTaskQueue(this)),
+      unbound_task_runner_(
+          new internal::MessageLoopTaskRunner(incoming_task_queue_)),
+      task_runner_(unbound_task_runner_) {
+  // If type is TYPE_CUSTOM non-null pump_factory must be given.
+  DCHECK_EQ(type_ == TYPE_CUSTOM, !pump_factory_.is_null());
+}
+
+void MessageLoop::BindToCurrentThread() {
+  DCHECK(!pump_);
+  if (!pump_factory_.is_null())
+    pump_ = pump_factory_.Run();
+  else
+    pump_ = CreateMessagePumpForType(type_);
+
   DCHECK(!current()) << "should only have one message loop per thread";
   lazy_tls_ptr.Pointer()->Set(this);
 
-  incoming_task_queue_ = new internal::IncomingTaskQueue(this);
-  message_loop_proxy_ =
-      new internal::MessageLoopProxyImpl(incoming_task_queue_);
-  thread_task_runner_handle_.reset(
-      new ThreadTaskRunnerHandle(message_loop_proxy_));
+  incoming_task_queue_->StartScheduling();
+  unbound_task_runner_->BindToCurrentThread();
+  unbound_task_runner_ = nullptr;
+  SetThreadTaskRunnerHandle();
+}
+
+void MessageLoop::SetTaskRunner(
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  DCHECK_EQ(this, current());
+  DCHECK(task_runner->BelongsToCurrentThread());
+  DCHECK(!unbound_task_runner_);
+  task_runner_ = std::move(task_runner);
+  SetThreadTaskRunnerHandle();
+}
+
+void MessageLoop::SetThreadTaskRunnerHandle() {
+  DCHECK_EQ(this, current());
+  // Clear the previous thread task runner first, because only one can exist at
+  // a time.
+  thread_task_runner_handle_.reset();
+  thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_));
 }
 
 void MessageLoop::RunHandler() {
@@ -439,10 +475,11 @@
 
   HistogramEvent(kTaskRunEvent);
 
+  TRACE_TASK_EXECUTION("MessageLoop::RunTask", pending_task);
+
   FOR_EACH_OBSERVER(TaskObserver, task_observers_,
                     WillProcessTask(pending_task));
-  task_annotator_.RunTask(
-      "MessageLoop::PostTask", "MessageLoop::RunTask", pending_task);
+  task_annotator_.RunTask("MessageLoop::PostTask", pending_task);
   FOR_EACH_OBSERVER(TaskObserver, task_observers_,
                     DidProcessTask(pending_task));
 
@@ -529,7 +566,7 @@
         "MsgLoop:" + thread_name_,
         kLeastNonZeroMessageId, kMaxMessageId,
         kNumberOfDistinctMessagesDisplayed,
-        message_histogram_->kHexRangePrintingFlag,
+        HistogramBase::kHexRangePrintingFlag,
         event_descriptions_);
   }
 #endif
@@ -579,7 +616,7 @@
     return false;
   }
 
-  // When we "fall behind," there will be a lot of tasks in the delayed work
+  // 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
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index fd7596a..6e4be9d 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -16,8 +16,7 @@
 #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_loop_task_runner.h"
 #include "base/message_loop/message_pump.h"
 #include "base/message_loop/timer_slack.h"
 #include "base/observer_list.h"
@@ -114,7 +113,8 @@
   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);
+  explicit MessageLoop(scoped_ptr<MessagePump> pump);
+
   ~MessageLoop() override;
 
   // Returns the MessageLoop object for the current thread, or null if none.
@@ -242,9 +242,6 @@
   // 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
@@ -268,9 +265,6 @@
   // 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.
@@ -295,33 +289,31 @@
   }
   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.
+  const scoped_refptr<SingleThreadTaskRunner>& task_runner() {
+    return task_runner_;
   }
 
-  // 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_;
-  }
+  // Sets a new TaskRunner for this message loop. The message loop must already
+  // have been bound to a thread prior to this call, and the task runner must
+  // belong to that thread. Note that changing the task runner will also affect
+  // the ThreadTaskRunnerHandle for the target thread. Must be called on the
+  // thread to which the message loop is bound.
+  void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
 
   // Enables or disables the recursive task processing. This happens in the case
-  // of recursive message loops. Some unwanted message loop may occurs when
+  // of recursive message loops. Some unwanted message loops may occur when
   // using common controls or printer functions. By default, recursive task
   // processing is disabled.
   //
-  // Please utilize |ScopedNestableTaskAllower| instead of calling these methods
-  // directly.  In general nestable message loops are to be avoided.  They are
+  // Please use |ScopedNestableTaskAllower| instead of calling these methods
+  // directly.  In general, nestable message loops are to be avoided.  They are
   // dangerous and difficult to get right, so please use with extreme caution.
   //
   // The specific case where tasks get queued is:
   // - The thread is running a message loop.
-  // - It receives a task #1 and execute it.
-  // - The task #1 implicitly start a message loop, like a MessageBox in the
+  // - It receives a task #1 and executes it.
+  // - The task #1 implicitly starts a message loop, like a MessageBox in the
   //   unit test. This can also be StartDoc or GetSaveFileName.
   // - The thread receives a task #2 before or while in this second message
   //   loop.
@@ -394,10 +386,6 @@
   // 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_; }
@@ -411,9 +399,37 @@
 
  private:
   friend class RunLoop;
+  friend class internal::IncomingTaskQueue;
+  friend class ScheduleWorkTest;
+  friend class Thread;
 
-  // Configures various members for the two constructors.
-  void Init();
+  using MessagePumpFactoryCallback = Callback<scoped_ptr<MessagePump>()>;
+
+  // Creates a MessageLoop without binding to a thread.
+  // If |type| is TYPE_CUSTOM non-null |pump_factory| must be also given
+  // to create a message pump for this message loop.  Otherwise a default
+  // message pump for the |type| is created.
+  //
+  // It is valid to call this to create a new message loop on one thread,
+  // and then pass it to the thread where the message loop actually runs.
+  // The message loop's BindToCurrentThread() method must be called on the
+  // thread the message loop runs on, before calling Run().
+  // Before BindToCurrentThread() is called, only Post*Task() functions can
+  // be called on the message loop.
+  static scoped_ptr<MessageLoop> CreateUnbound(
+      Type type,
+      MessagePumpFactoryCallback pump_factory);
+
+  // Common private constructor. Other constructors delegate the initialization
+  // to this constructor.
+  MessageLoop(Type type, MessagePumpFactoryCallback pump_factory);
+
+  // Configure various members and bind this message loop to the current thread.
+  void BindToCurrentThread();
+
+  // Sets the ThreadTaskRunnerHandle for the current thread to point to the
+  // task runner for this message loop.
+  void SetThreadTaskRunnerHandle();
 
   // Invokes the actual run loop using the message pump.
   void RunHandler();
@@ -437,6 +453,10 @@
   // empty.
   void ReloadWorkQueue();
 
+  // Wakes up the message pump. Can be called on any thread. The caller is
+  // responsible for synchronizing ScheduleWork() calls.
+  void ScheduleWork();
+
   // Start recording histogram info about events and action IF it was enabled
   // and IF the statistics recorder can accept a registration of our histogram.
   void StartHistogrammer();
@@ -485,11 +505,15 @@
   bool nestable_tasks_allowed_;
 
 #if defined(OS_WIN)
-  // Should be set to true before calling Windows APIs like TrackPopupMenu, etc
+  // Should be set to true before calling Windows APIs like TrackPopupMenu, etc.
   // which enter a modal message loop.
   bool os_modal_loop_;
 #endif
 
+  // pump_factory_.Run() is called to create a message pump for this loop
+  // if type_ is TYPE_CUSTOM and pump_ is null.
+  MessagePumpFactoryCallback pump_factory_;
+
   std::string thread_name_;
   // A profiling histogram showing the counts of various messages and events.
   HistogramBase* message_histogram_;
@@ -502,8 +526,11 @@
 
   scoped_refptr<internal::IncomingTaskQueue> incoming_task_queue_;
 
-  // The message loop proxy associated with this message loop.
-  scoped_refptr<internal::MessageLoopProxyImpl> message_loop_proxy_;
+  // A task runner which we haven't bound to a thread yet.
+  scoped_refptr<internal::MessageLoopTaskRunner> unbound_task_runner_;
+
+  // The task runner associated with this message loop.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
   scoped_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
 
   template <class T, class R> friend class base::subtle::DeleteHelperInternal;
@@ -574,8 +601,8 @@
 // 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);
+static_assert(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
+              "MessageLoopForUI should not have extra member variables");
 
 #endif  // !defined(OS_NACL)
 
@@ -655,8 +682,8 @@
 // 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);
+static_assert(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
+              "MessageLoopForIO should not have extra member variables");
 
 }  // namespace base
 
diff --git a/base/message_loop/message_loop_proxy.cc b/base/message_loop/message_loop_proxy.cc
deleted file mode 100644
index e5f0142..0000000
--- a/base/message_loop/message_loop_proxy.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All 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
deleted file mode 100644
index d5ecc04..0000000
--- a/base/message_loop/message_loop_proxy.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All 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.h b/base/message_loop/message_loop_proxy_impl.h
deleted file mode 100644
index 0fe629f..0000000
--- a/base/message_loop/message_loop_proxy_impl.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All 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
deleted file mode 100644
index fa25371..0000000
--- a/base/message_loop/message_loop_proxy_impl_unittest.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All 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
deleted file mode 100644
index 0b0d9f8..0000000
--- a/base/message_loop/message_loop_proxy_unittest.cc
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All 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_proxy_impl.cc b/base/message_loop/message_loop_task_runner.cc
similarity index 60%
rename from base/message_loop/message_loop_proxy_impl.cc
rename to base/message_loop/message_loop_task_runner.cc
index b7abca3..c9b5ffe 100644
--- a/base/message_loop/message_loop_proxy_impl.cc
+++ b/base/message_loop/message_loop_task_runner.cc
@@ -2,23 +2,27 @@
 // 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/message_loop/message_loop_task_runner.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(
+MessageLoopTaskRunner::MessageLoopTaskRunner(
     scoped_refptr<IncomingTaskQueue> incoming_queue)
-    : incoming_queue_(incoming_queue),
-      valid_thread_id_(PlatformThread::CurrentId()) {
+    : incoming_queue_(incoming_queue), valid_thread_id_(kInvalidThreadId) {
 }
 
-bool MessageLoopProxyImpl::PostDelayedTask(
+void MessageLoopTaskRunner::BindToCurrentThread() {
+  AutoLock lock(valid_thread_id_lock_);
+  DCHECK_EQ(kInvalidThreadId, valid_thread_id_);
+  valid_thread_id_ = PlatformThread::CurrentId();
+}
+
+bool MessageLoopTaskRunner::PostDelayedTask(
     const tracked_objects::Location& from_here,
     const base::Closure& task,
     base::TimeDelta delay) {
@@ -26,7 +30,7 @@
   return incoming_queue_->AddToIncomingQueue(from_here, task, delay, true);
 }
 
-bool MessageLoopProxyImpl::PostNonNestableDelayedTask(
+bool MessageLoopTaskRunner::PostNonNestableDelayedTask(
     const tracked_objects::Location& from_here,
     const base::Closure& task,
     base::TimeDelta delay) {
@@ -34,21 +38,14 @@
   return incoming_queue_->AddToIncomingQueue(from_here, task, delay, false);
 }
 
-bool MessageLoopProxyImpl::RunsTasksOnCurrentThread() const {
+bool MessageLoopTaskRunner::RunsTasksOnCurrentThread() const {
+  AutoLock lock(valid_thread_id_lock_);
   return valid_thread_id_ == PlatformThread::CurrentId();
 }
 
-MessageLoopProxyImpl::~MessageLoopProxyImpl() {
+MessageLoopTaskRunner::~MessageLoopTaskRunner() {
 }
 
 }  // 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_task_runner.h b/base/message_loop/message_loop_task_runner.h
new file mode 100644
index 0000000..dc2947d
--- /dev/null
+++ b/base/message_loop/message_loop_task_runner.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/pending_task.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace internal {
+
+class IncomingTaskQueue;
+
+// A stock implementation of SingleThreadTaskRunner that is created and managed
+// by a MessageLoop. For now a MessageLoopTaskRunner can only be created as
+// part of a MessageLoop.
+class BASE_EXPORT MessageLoopTaskRunner : public SingleThreadTaskRunner {
+ public:
+  explicit MessageLoopTaskRunner(
+      scoped_refptr<IncomingTaskQueue> incoming_queue);
+
+  // Initialize this message loop task runner on the current thread.
+  void BindToCurrentThread();
+
+  // SingleThreadTaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task,
+                       base::TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const base::Closure& task,
+                                  base::TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+ private:
+  friend class RefCountedThreadSafe<MessageLoopTaskRunner>;
+  ~MessageLoopTaskRunner() override;
+
+  // The incoming queue receiving all posted tasks.
+  scoped_refptr<IncomingTaskQueue> incoming_queue_;
+
+  // ID of the thread |this| was created on.  Could be accessed on multiple
+  // threads, protected by |valid_thread_id_lock_|.
+  PlatformThreadId valid_thread_id_;
+  mutable Lock valid_thread_id_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageLoopTaskRunner);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
diff --git a/base/message_loop/message_loop_task_runner_unittest.cc b/base/message_loop/message_loop_task_runner_unittest.cc
new file mode 100644
index 0000000..a0d84b7
--- /dev/null
+++ b/base/message_loop/message_loop_task_runner_unittest.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop_task_runner.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+class MessageLoopTaskRunnerTest : public testing::Test {
+ public:
+  MessageLoopTaskRunnerTest()
+      : current_loop_(new MessageLoop()),
+        task_thread_("task_thread"),
+        thread_sync_(true, false) {}
+
+  void DeleteCurrentMessageLoop() { current_loop_.reset(); }
+
+ protected:
+  void SetUp() override {
+    // Use SetUp() instead of the constructor to avoid posting a task to a
+    // partially constructed object.
+    task_thread_.Start();
+
+    // Allow us to pause the |task_thread_|'s MessageLoop.
+    task_thread_.message_loop()->PostTask(
+        FROM_HERE, Bind(&MessageLoopTaskRunnerTest::BlockTaskThreadHelper,
+                        Unretained(this)));
+  }
+
+  void TearDown() override {
+    // Make sure the |task_thread_| is not blocked, and stop the thread
+    // fully before destruction because its tasks may still depend on the
+    // |thread_sync_| event.
+    thread_sync_.Signal();
+    task_thread_.Stop();
+    DeleteCurrentMessageLoop();
+  }
+
+  // Make LoopRecorder threadsafe so that there is defined behavior even if a
+  // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
+  class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
+   public:
+    LoopRecorder(MessageLoop** run_on,
+                 MessageLoop** deleted_on,
+                 int* destruct_order)
+        : run_on_(run_on),
+          deleted_on_(deleted_on),
+          destruct_order_(destruct_order) {}
+
+    void RecordRun() { *run_on_ = MessageLoop::current(); }
+
+   private:
+    friend class RefCountedThreadSafe<LoopRecorder>;
+    ~LoopRecorder() {
+      *deleted_on_ = MessageLoop::current();
+      *destruct_order_ = g_order.GetNext();
+    }
+
+    MessageLoop** run_on_;
+    MessageLoop** deleted_on_;
+    int* destruct_order_;
+  };
+
+  static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+  }
+
+  static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void UnblockTaskThread() { thread_sync_.Signal(); }
+
+  void BlockTaskThreadHelper() { thread_sync_.Wait(); }
+
+  static StaticAtomicSequenceNumber g_order;
+
+  scoped_ptr<MessageLoop> current_loop_;
+  Thread task_thread_;
+
+ private:
+  base::WaitableEvent thread_sync_;
+};
+
+StaticAtomicSequenceNumber MessageLoopTaskRunnerTest::g_order;
+
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_Basic) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  ASSERT_TRUE(task_thread_.task_runner()->PostTaskAndReply(
+      FROM_HERE, Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+  current_loop_->Run();
+
+  EXPECT_EQ(task_thread_.message_loop(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Grab a task runner to a dead MessageLoop.
+  scoped_refptr<SingleThreadTaskRunner> task_runner =
+      task_thread_.task_runner();
+  UnblockTaskThread();
+  task_thread_.Stop();
+
+  ASSERT_FALSE(
+      task_runner->PostTaskAndReply(FROM_HERE, Bind(&RecordLoop, task_recoder),
+                                    Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // The relay should have properly deleted its resources leaving us as the only
+  // reference.
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+  ASSERT_TRUE(task_recoder->HasOneRef());
+  ASSERT_TRUE(reply_recoder->HasOneRef());
+
+  // Nothing should have run though.
+  EXPECT_FALSE(task_run_on);
+  EXPECT_FALSE(reply_run_on);
+}
+
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_SameLoop) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  ASSERT_TRUE(current_loop_->task_runner()->PostTaskAndReply(
+      FROM_HERE, Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  current_loop_->Run();
+
+  EXPECT_EQ(current_loop_.get(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
+  // Annotate the scope as having memory leaks to suppress heapchecker reports.
+  ANNOTATE_SCOPED_MEMORY_LEAK;
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  task_thread_.task_runner()->PostTaskAndReply(
+      FROM_HERE, Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+
+  // Mercilessly whack the current loop before |reply| gets to run.
+  current_loop_.reset();
+
+  // This should ensure the relay has been run.  We need to record the
+  // MessageLoop pointer before stopping the thread because Thread::Stop() will
+  // NULL out its own pointer.
+  MessageLoop* task_loop = task_thread_.message_loop();
+  task_thread_.Stop();
+
+  EXPECT_EQ(task_loop, task_run_on);
+  ASSERT_FALSE(task_deleted_on);
+  EXPECT_FALSE(reply_run_on);
+  ASSERT_FALSE(reply_deleted_on);
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+
+  // The PostTaskAndReplyRelay is leaked here.  Even if we had a reference to
+  // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
+  // checks that MessageLoop::current() is the the same as when the
+  // PostTaskAndReplyRelay object was constructed.  However, this loop must have
+  // already been deleted in order to perform this test.  See
+  // http://crbug.com/86301.
+}
+
+class MessageLoopTaskRunnerThreadingTest : public testing::Test {
+ public:
+  void Release() const {
+    AssertOnIOThread();
+    Quit();
+  }
+
+  void Quit() const {
+    loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+  }
+
+  void AssertOnIOThread() const {
+    ASSERT_TRUE(io_thread_->task_runner()->BelongsToCurrentThread());
+    ASSERT_EQ(io_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
+  }
+
+  void AssertOnFileThread() const {
+    ASSERT_TRUE(file_thread_->task_runner()->BelongsToCurrentThread());
+    ASSERT_EQ(file_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
+  }
+
+ protected:
+  void SetUp() override {
+    io_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_IO"));
+    file_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_File"));
+    io_thread_->Start();
+    file_thread_->Start();
+  }
+
+  void TearDown() override {
+    io_thread_->Stop();
+    file_thread_->Stop();
+  }
+
+  static void BasicFunction(MessageLoopTaskRunnerThreadingTest* test) {
+    test->AssertOnFileThread();
+    test->Quit();
+  }
+
+  static void AssertNotRun() { FAIL() << "Callback Should not get executed."; }
+
+  class DeletedOnFile {
+   public:
+    explicit DeletedOnFile(MessageLoopTaskRunnerThreadingTest* test)
+        : test_(test) {}
+
+    ~DeletedOnFile() {
+      test_->AssertOnFileThread();
+      test_->Quit();
+    }
+
+   private:
+    MessageLoopTaskRunnerThreadingTest* test_;
+  };
+
+  scoped_ptr<Thread> io_thread_;
+  scoped_ptr<Thread> file_thread_;
+
+ private:
+  mutable MessageLoop loop_;
+};
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, Release) {
+  EXPECT_TRUE(io_thread_->task_runner()->ReleaseSoon(FROM_HERE, this));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, Delete) {
+  DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
+  EXPECT_TRUE(
+      file_thread_->task_runner()->DeleteSoon(FROM_HERE, deleted_on_file));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTask) {
+  EXPECT_TRUE(file_thread_->task_runner()->PostTask(
+      FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::BasicFunction,
+                      Unretained(this))));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadExits) {
+  scoped_ptr<Thread> test_thread(
+      new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
+  test_thread->Start();
+  scoped_refptr<SingleThreadTaskRunner> task_runner =
+      test_thread->task_runner();
+  test_thread->Stop();
+
+  bool ret = task_runner->PostTask(
+      FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadIsDeleted) {
+  scoped_refptr<SingleThreadTaskRunner> task_runner;
+  {
+    scoped_ptr<Thread> test_thread(
+        new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
+    test_thread->Start();
+    task_runner = test_thread->task_runner();
+  }
+  bool ret = task_runner->PostTask(
+      FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_test.cc b/base/message_loop/message_loop_test.cc
index eca6c8f..f821220 100644
--- a/base/message_loop/message_loop_test.cc
+++ b/base/message_loop/message_loop_test.cc
@@ -4,6 +4,8 @@
 
 #include "base/message_loop/message_loop_test.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
@@ -87,7 +89,7 @@
 
 void RunTest_PostTask(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
   // Add tests to message loop
   scoped_refptr<Foo> foo(new Foo());
   std::string a("a"), b("b"), c("c"), d("d");
@@ -104,8 +106,9 @@
   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())));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&MessageLoop::QuitWhenIdle, Unretained(MessageLoop::current())));
 
   // Now kick things off
   MessageLoop::current()->Run();
@@ -116,7 +119,7 @@
 
 void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   // Test that PostDelayedTask results in a delayed task.
 
@@ -139,7 +142,7 @@
 
 void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   // Test that two tasks with different delays run in the right order.
   int num_tasks = 2;
@@ -164,7 +167,7 @@
 
 void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   // Test that two tasks with the same delay run in the order in which they
   // were posted.
@@ -194,7 +197,7 @@
 
 void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   // Test that a delayed task still runs after a normal tasks even if the
   // normal tasks take a long time to run.
@@ -221,7 +224,7 @@
 
 void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   // Test that a delayed task still runs after a pile of normal tasks.  The key
   // difference between this test and the previous one is that here we return
@@ -249,7 +252,7 @@
 
 void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   // Test that the interval of the timer, used to run the next delayed task, is
   // set to a value corresponding to when the next delayed task should run.
@@ -316,7 +319,7 @@
   bool b_was_deleted = false;
   {
     scoped_ptr<MessagePump> pump(factory());
-    MessageLoop loop(pump.Pass());
+    MessageLoop loop(std::move(pump));
     loop.PostTask(
         FROM_HERE, Bind(&RecordDeletionProbe::Run,
                               new RecordDeletionProbe(NULL, &a_was_deleted)));
@@ -336,7 +339,7 @@
   bool c_was_deleted = false;
   {
     scoped_ptr<MessagePump> pump(factory());
-    MessageLoop loop(pump.Pass());
+    MessageLoop loop(std::move(pump));
     // The scoped_refptr for each of the below is held either by the chained
     // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
     RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted);
@@ -363,7 +366,7 @@
 
 void RunTest_Nesting(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   int depth = 100;
   MessageLoop::current()->PostTask(FROM_HERE,
@@ -471,7 +474,7 @@
 }
 void RunTest_RecursiveDenial1(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
   TaskList order;
@@ -518,7 +521,7 @@
 
 void RunTest_RecursiveDenial3(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
   TaskList order;
@@ -559,7 +562,7 @@
 
 void RunTest_RecursiveSupport1(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
   MessageLoop::current()->PostTask(
@@ -592,7 +595,7 @@
 // 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());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -634,7 +637,7 @@
 void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory,
                                      bool use_delayed) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -702,7 +705,7 @@
 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
 void RunTest_QuitNow(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -737,7 +740,7 @@
 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
 void RunTest_RunLoopQuitTop(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -767,7 +770,7 @@
 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
 void RunTest_RunLoopQuitNested(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -797,7 +800,7 @@
 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
 void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -830,7 +833,7 @@
 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
 void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -899,7 +902,7 @@
 // Tests RunLoopQuit works before RunWithID.
 void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -920,7 +923,7 @@
 // Tests RunLoopQuit works during RunWithID.
 void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -947,7 +950,7 @@
 // Tests RunLoopQuit works after RunWithID.
 void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory) {
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
 
   TaskList order;
 
@@ -1005,7 +1008,7 @@
 void RunTest_RecursivePosts(MessagePumpFactory factory) {
   const int kNumTimes = 1 << 17;
   scoped_ptr<MessagePump> pump(factory());
-  MessageLoop loop(pump.Pass());
+  MessageLoop loop(std::move(pump));
   loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumTimes));
   loop.Run();
 }
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
index ddde6bb..dcac662 100644
--- a/base/message_loop/message_loop_unittest.cc
+++ b/base/message_loop/message_loop_unittest.cc
@@ -10,12 +10,12 @@
 #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/test/test_simple_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
@@ -119,7 +119,7 @@
       Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
       TimeDelta::FromSeconds(1000));
 
-  // This slightly delayed task should run from within SubPumpFunc).
+  // This slightly delayed task should run from within SubPumpFunc.
   loop.PostDelayedTask(
       FROM_HERE,
       Bind(&PostQuitMessage, 0),
@@ -600,7 +600,7 @@
   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?
+  // TODO(ajwong): Do we really need such long Sleeps in this function?
   // Make sure the thread runs and sleeps for lack of work.
   TimeDelta delay = TimeDelta::FromMilliseconds(100);
   PlatformThread::Sleep(delay);
@@ -645,7 +645,7 @@
   RunTest_PostDelayedTask_SharedTimer_SubPump();
 }
 
-// This test occasionally hangs http://crbug.com/44567
+// This test occasionally hangs. See http://crbug.com/44567.
 TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
   RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
   RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
@@ -653,7 +653,7 @@
 }
 
 TEST(MessageLoopTest, RecursiveSupport2) {
-  // This test requires a UI loop
+  // This test requires a UI loop.
   RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
 }
 #endif  // defined(OS_WIN)
@@ -907,8 +907,9 @@
       &Foo::Test1ConstRef, foo.get(), a));
 
   // Post quit task;
-  MessageLoop::current()->PostTask(FROM_HERE, Bind(
-      &MessageLoop::Quit, Unretained(MessageLoop::current())));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&MessageLoop::QuitWhenIdle, Unretained(MessageLoop::current())));
 
   // Now kick things off
   MessageLoop::current()->Run();
@@ -983,7 +984,7 @@
         break;
     }
     EXPECT_TRUE(did_run);
-    MessageLoop::current()->Quit();
+    MessageLoop::current()->QuitWhenIdle();
     break;
   }
   return 0;
@@ -1012,4 +1013,26 @@
 }
 #endif  // defined(OS_WIN)
 
+TEST(MessageLoopTest, SetTaskRunner) {
+  MessageLoop loop;
+  scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+
+  loop.SetTaskRunner(new_runner);
+  EXPECT_EQ(new_runner, loop.task_runner());
+  EXPECT_EQ(new_runner, ThreadTaskRunnerHandle::Get());
+}
+
+TEST(MessageLoopTest, OriginalRunnerWorks) {
+  MessageLoop loop;
+  scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+  scoped_refptr<SingleThreadTaskRunner> original_runner(loop.task_runner());
+  loop.SetTaskRunner(new_runner);
+
+  scoped_refptr<Foo> foo(new Foo());
+  original_runner->PostTask(FROM_HERE,
+                            Bind(&Foo::Test1ConstRef, foo.get(), "a"));
+  loop.RunUntilIdle();
+  EXPECT_EQ(1, foo->test_count());
+}
+
 }  // namespace base
diff --git a/base/message_loop/message_pump_android.cc b/base/message_loop/message_pump_android.cc
index babd17b..a0eee12 100644
--- a/base/message_loop/message_pump_android.cc
+++ b/base/message_loop/message_pump_android.cc
@@ -21,8 +21,10 @@
 // ----------------------------------------------------------------------------
 // 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) {
+static void DoRunLoopOnce(JNIEnv* env,
+                          const JavaParamRef<jobject>& obj,
+                          jlong native_delegate,
+                          jlong delayed_scheduled_time_ticks) {
   base::MessagePump::Delegate* delegate =
       reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
   DCHECK(delegate);
diff --git a/base/message_loop/message_pump_default.cc b/base/message_loop/message_pump_default.cc
index bb9d8ce..27c19e0 100644
--- a/base/message_loop/message_pump_default.cc
+++ b/base/message_loop/message_pump_default.cc
@@ -52,8 +52,7 @@
       event_.Wait();
     } else {
       TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
-      // If the delay is under 1 ms we need to execute the task right away.
-      if (delay.InMilliseconds() >= 1) {
+      if (delay > TimeDelta()) {
         event_.TimedWait(delay);
       } else {
         // It looks like delayed_work_time_ indicates a time in the past, so we
diff --git a/base/message_loop/message_pump_glib.cc b/base/message_loop/message_pump_glib.cc
index f06f60d..fd23745 100644
--- a/base/message_loop/message_pump_glib.cc
+++ b/base/message_loop/message_pump_glib.cc
@@ -52,7 +52,7 @@
 // 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
+// NOTE: It is common for subsystems to want to process pending events while
 // doing intensive work, for example the flash plugin. They usually use the
 // following pattern (recommended by the GTK docs):
 // while (gtk_events_pending()) {
@@ -350,7 +350,7 @@
 
 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.
+  // adjusted.  This will cause us to try to do work, but that's OK.
   delayed_work_time_ = delayed_work_time;
   ScheduleWork();
 }
diff --git a/base/message_loop/message_pump_libevent.cc b/base/message_loop/message_pump_libevent.cc
index b5b1fb7..74602a7 100644
--- a/base/message_loop/message_pump_libevent.cc
+++ b/base/message_loop/message_pump_libevent.cc
@@ -55,13 +55,17 @@
     : event_(NULL),
       pump_(NULL),
       watcher_(NULL),
-      weak_factory_(this) {
+      was_destroyed_(NULL) {
 }
 
 MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
   if (event_) {
     StopWatchingFileDescriptor();
   }
+  if (was_destroyed_) {
+    DCHECK(!*was_destroyed_);
+    *was_destroyed_ = true;
+  }
 }
 
 bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
@@ -340,23 +344,31 @@
 }
 
 // static
-void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
+void MessagePumpLibevent::OnLibeventNotification(int fd,
+                                                 short flags,
                                                  void* context) {
-  WeakPtr<FileDescriptorWatcher> controller =
-      static_cast<FileDescriptorWatcher*>(context)->weak_factory_.GetWeakPtr();
-  DCHECK(controller.get());
+  FileDescriptorWatcher* controller =
+      static_cast<FileDescriptorWatcher*>(context);
+  DCHECK(controller);
   TRACE_EVENT1("toplevel", "MessagePumpLibevent::OnLibeventNotification",
                "fd", fd);
 
   MessagePumpLibevent* pump = controller->pump();
   pump->processed_io_events_ = true;
 
-  if (flags & EV_WRITE) {
+  if ((flags & (EV_READ | EV_WRITE)) == (EV_READ | EV_WRITE)) {
+    // Both callbacks will be called. It is necessary to check that |controller|
+    // is not destroyed.
+    bool controller_was_destroyed = false;
+    controller->was_destroyed_ = &controller_was_destroyed;
     controller->OnFileCanWriteWithoutBlocking(fd, pump);
-  }
-  // Check |controller| in case it's been deleted in
-  // controller->OnFileCanWriteWithoutBlocking().
-  if (controller.get() && flags & EV_READ) {
+    if (!controller_was_destroyed)
+      controller->OnFileCanReadWithoutBlocking(fd, pump);
+    if (!controller_was_destroyed)
+      controller->was_destroyed_ = nullptr;
+  } else if (flags & EV_WRITE) {
+    controller->OnFileCanWriteWithoutBlocking(fd, pump);
+  } else if (flags & EV_READ) {
     controller->OnFileCanReadWithoutBlocking(fd, pump);
   }
 }
diff --git a/base/message_loop/message_pump_libevent.h b/base/message_loop/message_pump_libevent.h
index 3f5ad51..8b815ae 100644
--- a/base/message_loop/message_pump_libevent.h
+++ b/base/message_loop/message_pump_libevent.h
@@ -7,7 +7,6 @@
 
 #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"
@@ -86,7 +85,9 @@
     event* event_;
     MessagePumpLibevent* pump_;
     Watcher* watcher_;
-    WeakPtrFactory<FileDescriptorWatcher> weak_factory_;
+    // If this pointer is non-NULL, the pointee is set to true in the
+    // destructor.
+    bool* was_destroyed_;
 
     DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
   };
diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc
index 65d7217..e911905 100644
--- a/base/message_loop/message_pump_libevent_unittest.cc
+++ b/base/message_loop/message_pump_libevent_unittest.cc
@@ -77,7 +77,13 @@
 
 // Test to make sure that we catch calling WatchFileDescriptor off of the
 // wrong thread.
-TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) {
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+// Flaky on Chrome OS and Linux: crbug.com/138845.
+#define MAYBE_TestWatchingFromBadThread DISABLED_TestWatchingFromBadThread
+#else
+#define MAYBE_TestWatchingFromBadThread TestWatchingFromBadThread
+#endif
+TEST_F(MessagePumpLibeventTest, MAYBE_TestWatchingFromBadThread) {
   MessagePumpLibevent::FileDescriptorWatcher watcher;
   StupidWatcher delegate;
 
@@ -240,7 +246,7 @@
   MessagePumpLibevent::FileDescriptorWatcher controller;
   QuitWatcher delegate(&controller, &run_loop);
   WaitableEvent event(false /* manual_reset */, false /* initially_signaled */);
-  WaitableEventWatcher watcher;
+  scoped_ptr<WaitableEventWatcher> watcher(new WaitableEventWatcher);
 
   // Tell the pump to watch the pipe.
   pump->WatchFileDescriptor(pipefds_[0], false, MessagePumpLibevent::WATCH_READ,
@@ -252,13 +258,17 @@
       Bind(&WriteFDWrapper, pipefds_[1], &buf, 1);
   io_loop()->PostTask(FROM_HERE,
                       Bind(IgnoreResult(&WaitableEventWatcher::StartWatching),
-                           Unretained(&watcher), &event, write_fd_task));
+                           Unretained(watcher.get()), &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();
+
+  // StartWatching can move |watcher| to IO thread. Release on IO thread.
+  io_loop()->PostTask(FROM_HERE, Bind(&WaitableEventWatcher::StopWatching,
+                                      Owned(watcher.release())));
 }
 
 }  // namespace
diff --git a/base/message_loop/message_pump_mac.h b/base/message_loop/message_pump_mac.h
index c853202..c46f261 100644
--- a/base/message_loop/message_pump_mac.h
+++ b/base/message_loop/message_pump_mac.h
@@ -22,7 +22,7 @@
 //
 // 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.
+// any other thread, one of the other concrete subclasses is preferable.
 // MessagePumpMac::Create is defined, which returns a new NSApplication-based
 // or NSRunLoop-based MessagePump subclass depending on which thread it is
 // called on.
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm
index 914977b..53e3363 100644
--- a/base/message_loop/message_pump_mac.mm
+++ b/base/message_loop/message_pump_mac.mm
@@ -10,6 +10,7 @@
 #include <limits>
 
 #include "base/logging.h"
+#include "base/mac/call_with_eh_frame.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/message_loop/timer_slack.h"
 #include "base/run_loop.h"
@@ -300,7 +301,9 @@
 // static
 void MessagePumpCFRunLoopBase::RunWorkSource(void* info) {
   MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
-  self->RunWork();
+  base::mac::CallWithEHFrame(^{
+    self->RunWork();
+  });
 }
 
 // Called by MessagePumpCFRunLoopBase::RunWorkSource.
@@ -359,7 +362,9 @@
 // static
 void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
   MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
-  self->RunIdleWork();
+  base::mac::CallWithEHFrame(^{
+    self->RunIdleWork();
+  });
 }
 
 // Called by MessagePumpCFRunLoopBase::RunIdleWorkSource.
@@ -393,7 +398,9 @@
 // static
 void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) {
   MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
-  self->RunNestingDeferredWork();
+  base::mac::CallWithEHFrame(^{
+    self->RunNestingDeferredWork();
+  });
 }
 
 // Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource.
@@ -440,15 +447,16 @@
                                                CFRunLoopActivity activity,
                                                void* info) {
   MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  base::mac::CallWithEHFrame(^{
+    // Attempt to do some idle work before going to sleep.
+    self->RunIdleWork();
 
-  // 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();
+    // 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.
@@ -463,7 +471,9 @@
   // 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();
+  base::mac::CallWithEHFrame(^{
+    self->MaybeScheduleNestingDeferredWork();
+  });
 }
 
 // Called from the run loop.
@@ -498,7 +508,9 @@
       // 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();
+      base::mac::CallWithEHFrame(^{
+        self->MaybeScheduleNestingDeferredWork();
+      });
       --self->nesting_level_;
       break;
 
@@ -506,7 +518,9 @@
       break;
   }
 
-  self->EnterExitRunLoop(activity);
+  base::mac::CallWithEHFrame(^{
+    self->EnterExitRunLoop(activity);
+  });
 }
 
 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop.  The default
diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc
index b3e5604..c568425 100644
--- a/base/message_loop/message_pump_perftest.cc
+++ b/base/message_loop/message_pump_perftest.cc
@@ -20,19 +20,23 @@
 #endif
 
 namespace base {
-namespace {
 
 class ScheduleWorkTest : public testing::Test {
  public:
   ScheduleWorkTest() : counter_(0) {}
 
+  void SetUp() override {
+    if (base::ThreadTicks::IsSupported())
+      base::ThreadTicks::WaitUntilInitialized();
+  }
+
   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::ThreadTicks thread_start;
+    if (ThreadTicks::IsSupported())
+      thread_start = base::ThreadTicks::Now();
     base::TimeDelta minimum = base::TimeDelta::Max();
     base::TimeDelta maximum = base::TimeDelta();
     base::TimeTicks now, lastnow = start;
@@ -50,9 +54,9 @@
     } while (now - start < base::TimeDelta::FromSeconds(kTargetTimeSec));
 
     scheduling_times_[index] = now - start;
-    if (TimeTicks::IsThreadNowSupported())
+    if (ThreadTicks::IsSupported())
       scheduling_thread_times_[index] =
-          base::TimeTicks::ThreadNow() - thread_start;
+          base::ThreadTicks::Now() - thread_start;
     min_batch_times_[index] = minimum;
     max_batch_times_[index] = maximum;
     target_message_loop()->PostTask(FROM_HERE,
@@ -71,16 +75,24 @@
     {
       target_.reset(new Thread("target"));
       target_->StartWithOptions(Thread::Options(target_type, 0u));
+
+      // Without this, it's possible for the scheduling threads to start and run
+      // before the target thread. In this case, the scheduling threads will
+      // call target_message_loop()->ScheduleWork(), which dereferences the
+      // loop's message pump, which is only created after the target thread has
+      // finished starting.
+      target_->WaitUntilThreadStarted();
     }
 
-    ScopedVector<Thread> scheduling_threads;
+    std::vector<scoped_ptr<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.push_back(
+          make_scoped_ptr(new Thread("posting thread")));
       scheduling_threads[i]->Start();
     }
 
@@ -140,7 +152,7 @@
         max_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
         "us/task",
         false);
-    if (TimeTicks::IsThreadNowSupported()) {
+    if (ThreadTicks::IsSupported()) {
       perf_test::PrintResult(
           "task",
           "_thread_time",
@@ -224,9 +236,6 @@
 }
 #endif
 
-static void DoNothing() {
-}
-
 class FakeMessagePump : public MessagePump {
  public:
   FakeMessagePump() {}
@@ -289,5 +298,4 @@
   Run(1000, 100);
 }
 
-}  // namespace
 }  // namespace base
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
index 27b47e1..14e4320 100644
--- a/base/message_loop/message_pump_win.cc
+++ b/base/message_loop/message_pump_win.cc
@@ -10,7 +10,6 @@
 #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"
@@ -122,44 +121,8 @@
 }
 
 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);
+  RescheduleTimer();
 }
 
 //-----------------------------------------------------------------------------
@@ -168,11 +131,6 @@
 // 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();
@@ -181,12 +139,6 @@
       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);
 }
 
@@ -318,6 +270,8 @@
   // needs to do more work.
   if (state_->delegate->DoWork())
     ScheduleWork();
+  state_->delegate->DoDelayedWork(&delayed_work_time_);
+  RescheduleTimer();
 }
 
 void MessagePumpForUI::HandleTimerMessage() {
@@ -330,18 +284,55 @@
     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_);
+  RescheduleTimer();
+}
+
+void MessagePumpForUI::RescheduleTimer() {
+  if (delayed_work_time_.is_null())
+    return;
+  //
+  // We would *like* to provide high resolution timers.  Windows timers using
+  // SetTimer() have a 10ms granularity.  We have to use WM_TIMER as a wakeup
+  // mechanism because the application can enter modal windows loops where it
+  // is not running our MessageLoop; the only way to have our timers fire in
+  // these cases is to post messages there.
+  //
+  // To provide sub-10ms timers, we process timers directly from our run loop.
+  // For the common case, timers will be processed there as the run loop does
+  // its normal work.  However, we *also* set the system timer so that WM_TIMER
+  // events fire.  This mops up the case of timers not being able to work in
+  // modal message loops.  It is possible for the SetTimer to pop and have no
+  // pending timers, because they could have already been processed by the
+  // run loop itself.
+  //
+  // We use a single SetTimer corresponding to the timer that will expire
+  // soonest.  As new timers are created and destroyed, we update SetTimer.
+  // Getting a spurious SetTimer event firing is benign, as we'll just be
+  // processing an empty timer queue.
+  //
+  int delay_msec = GetCurrentDelay();
+  DCHECK_GE(delay_msec, 0);
+  if (delay_msec == 0) {
+    ScheduleWork();
+  } else {
+    if (delay_msec < USER_TIMER_MINIMUM)
+      delay_msec = USER_TIMER_MINIMUM;
+
+    // Create a WM_TIMER event that will wake us up to check for any pending
+    // timers (in case we are running within a nested, external sub-pump).
+    BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this),
+                        delay_msec, NULL);
+    if (ret)
+      return;
+    // If we can't set timers, we are in big trouble... but cross our fingers
+    // for now.
+    // TODO(jar): If we don't see this error, use a CHECK() here instead.
+    UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
+                              MESSAGE_LOOP_PROBLEM_MAX);
   }
 }
 
 bool MessagePumpForUI::ProcessNextWindowsMessage() {
-  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
-  tracked_objects::ScopedTracker tracking_profile1(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "440919 MessagePumpForUI::ProcessNextWindowsMessage1"));
-
   // If there are sent messages in the queue then PeekMessage internally
   // dispatches the message and returns false. We return true in this
   // case to ensure that the message loop peeks again instead of calling
@@ -351,11 +342,6 @@
   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);
@@ -364,11 +350,6 @@
 }
 
 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) {
@@ -383,43 +364,16 @@
   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"));
-
+  if (state_->dispatcher)
     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);
   }
 
@@ -632,8 +586,8 @@
 }
 
 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
-  if (this == reinterpret_cast<MessagePumpForIO*>(item.context) &&
-      this == reinterpret_cast<MessagePumpForIO*>(item.handler)) {
+  if (reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.context) &&
+      reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.handler)) {
     // This is our internal completion.
     DCHECK(!item.bytes_transfered);
     InterlockedExchange(&have_work_, 0);
diff --git a/base/message_loop/message_pump_win.h b/base/message_loop/message_pump_win.h
index 00f1287..9f1838d 100644
--- a/base/message_loop/message_pump_win.h
+++ b/base/message_loop/message_pump_win.h
@@ -78,7 +78,7 @@
 // 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
+// The basic structure of the extension (referred 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
@@ -130,6 +130,7 @@
   void WaitForWork();
   void HandleWorkMessage();
   void HandleTimerMessage();
+  void RescheduleTimer();
   bool ProcessNextWindowsMessage();
   bool ProcessMessageHelper(const MSG& msg);
   bool ProcessPumpReplacementMessage();
diff --git a/base/metrics/BUILD.gn b/base/metrics/BUILD.gn
index 845ac4f..6dd212f 100644
--- a/base/metrics/BUILD.gn
+++ b/base/metrics/BUILD.gn
@@ -20,6 +20,8 @@
     "histogram_samples.h",
     "histogram_snapshot_manager.cc",
     "histogram_snapshot_manager.h",
+    "metrics_hashes.cc",
+    "metrics_hashes.h",
     "sample_map.cc",
     "sample_map.h",
     "sample_vector.cc",
@@ -33,16 +35,18 @@
     "user_metrics_action.h",
   ]
 
-  if (is_nacl) {
-    sources -= [ "field_trial.cc" ]
-  }
-
   configs += [ "//base:base_implementation" ]
 
   deps = [
     "//base/debug",
     "//base/json",
     "//base/memory",
+    "//base/process",
+  ]
+
+  allow_circular_includes_from = [
+    "//base/memory",
+    "//base/process",
   ]
 
   visibility = [ "//base/*" ]
diff --git a/base/metrics/bucket_ranges.h b/base/metrics/bucket_ranges.h
index fe1152f..eb330f4 100644
--- a/base/metrics/bucket_ranges.h
+++ b/base/metrics/bucket_ranges.h
@@ -21,7 +21,6 @@
 
 #include "base/base_export.h"
 #include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
 #include "base/metrics/histogram_base.h"
 
 namespace base {
@@ -72,7 +71,7 @@
 
 //////////////////////////////////////////////////////////////////////////////
 // Expose only for test.
-BASE_EXPORT_PRIVATE extern const uint32 kCrcTable[256];
+BASE_EXPORT extern const uint32 kCrcTable[256];
 
 }  // namespace base
 
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index 639f6d3..e9e3be2 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -13,7 +13,6 @@
 #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 {
 
@@ -140,6 +139,11 @@
   return group_name_;
 }
 
+const std::string& FieldTrial::GetGroupNameWithoutActivation() {
+  FinalizeGroupChoice();
+  return group_name_;
+}
+
 void FieldTrial::SetForced() {
   // We might have been forced before (e.g., by CreateFieldTrial) and it's
   // first come first served, e.g., command line switch has precedence.
@@ -321,12 +325,11 @@
         // group number, so that it does not conflict with the |AppendGroup()|
         // result for the chosen group.
         const int kNonConflictingGroupNumber = -2;
-        COMPILE_ASSERT(
+        static_assert(
             kNonConflictingGroupNumber != FieldTrial::kDefaultGroupNumber,
-            conflicting_default_group_number);
-        COMPILE_ASSERT(
-            kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
-            conflicting_default_group_number);
+            "The 'non-conflicting' group number conflicts");
+        static_assert(kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
+                      "The 'non-conflicting' group number conflicts");
         *default_group_number = kNonConflictingGroupNumber;
       }
     }
@@ -355,32 +358,39 @@
 }
 
 // static
-FieldTrial* FieldTrialList::Find(const std::string& name) {
+FieldTrial* FieldTrialList::Find(const std::string& trial_name) {
   if (!global_)
     return NULL;
   AutoLock auto_lock(global_->lock_);
-  return global_->PreLockedFind(name);
+  return global_->PreLockedFind(trial_name);
 }
 
 // static
-int FieldTrialList::FindValue(const std::string& name) {
-  FieldTrial* field_trial = Find(name);
+int FieldTrialList::FindValue(const std::string& trial_name) {
+  FieldTrial* field_trial = Find(trial_name);
   if (field_trial)
     return field_trial->group();
   return FieldTrial::kNotFinalized;
 }
 
 // static
-std::string FieldTrialList::FindFullName(const std::string& name) {
-  FieldTrial* field_trial = Find(name);
+std::string FieldTrialList::FindFullName(const std::string& trial_name) {
+  FieldTrial* field_trial = Find(trial_name);
   if (field_trial)
     return field_trial->group_name();
   return std::string();
 }
 
 // static
-bool FieldTrialList::TrialExists(const std::string& name) {
-  return Find(name) != NULL;
+bool FieldTrialList::TrialExists(const std::string& trial_name) {
+  return Find(trial_name) != NULL;
+}
+
+// static
+bool FieldTrialList::IsTrialActive(const std::string& trial_name) {
+  FieldTrial* field_trial = Find(trial_name);
+  FieldTrial::ActiveGroup active_group;
+  return field_trial && field_trial->GetActiveGroup(&active_group);
 }
 
 // static
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 26257ab..899d89a 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -149,6 +149,11 @@
   // is used as the group name. This causes a winner to be chosen if none was.
   const std::string& group_name();
 
+  // Finalizes the group choice and returns the chosen group, but does not mark
+  // the trial as active - so its state will not be reported until group_name()
+  // or similar is called.
+  const std::string& GetGroupNameWithoutActivation();
+
   // Set the field trial as forced, meaning that it was setup earlier than
   // the hard coded registration of the field trial to override it.
   // This allows the code that was hard coded to register the field trial to
@@ -396,20 +401,25 @@
       uint32 randomization_seed,
       int* default_group_number);
 
-  // The Find() method can be used to test to see if a named Trial was already
+  // 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);
+  static FieldTrial* Find(const std::string& trial_name);
 
   // Returns the group number chosen for the named trial, or
   // FieldTrial::kNotFinalized if the trial does not exist.
-  static int FindValue(const std::string& name);
+  static int FindValue(const std::string& trial_name);
 
-  // Returns the group name chosen for the named trial, or the
-  // empty string if the trial does not exist.
-  static std::string FindFullName(const std::string& name);
+  // Returns the group name chosen for the named trial, or the empty string if
+  // the trial does not exist. The first call of this function on a given field
+  // trial will mark it as active, so that its state will be reported with usage
+  // metrics, crashes, etc.
+  static std::string FindFullName(const std::string& trial_name);
 
   // Returns true if the named trial has been registered.
-  static bool TrialExists(const std::string& name);
+  static bool TrialExists(const std::string& trial_name);
+
+  // Returns true if the named trial exists and has been activated.
+  static bool IsTrialActive(const std::string& trial_name);
 
   // Creates a persistent representation of active FieldTrial instances for
   // resurrection in another process. This allows randomization to be done in
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index f1a1042..6cecc00 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -72,6 +72,8 @@
  private:
   MessageLoop message_loop_;
   FieldTrialList trial_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrialTest);
 };
 
 // Test registration, and also check that destructors are called for trials
@@ -376,6 +378,28 @@
   EXPECT_EQ(active_group.group_name, active_groups[0].group_name);
 }
 
+TEST_F(FieldTrialTest, GetGroupNameWithoutActivation) {
+  const char kTrialName[] = "TestTrial";
+  const char kSecondaryGroupName[] = "SecondaryGroup";
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->AppendGroup(kSecondaryGroupName, 50);
+
+  // The trial should start inactive.
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
+
+  // Calling |GetGroupNameWithoutActivation()| should not activate the trial.
+  std::string group_name = trial->GetGroupNameWithoutActivation();
+  EXPECT_FALSE(group_name.empty());
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
+
+  // Calling |group_name()| should activate it and return the same group name.
+  EXPECT_EQ(group_name, trial->group_name());
+  EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
+}
+
 TEST_F(FieldTrialTest, Save) {
   std::string save_string;
 
@@ -1021,9 +1045,9 @@
     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);
+      trial->AppendGroup(base::IntToString(j), 1);
 
-    EXPECT_EQ(base::StringPrintf("%d", i), trial->group_name());
+    EXPECT_EQ(base::IntToString(i), trial->group_name());
   }
 }
 
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 42ced3d..1bbcab7 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -17,6 +17,7 @@
 #include "base/compiler_specific.h"
 #include "base/debug/alias.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/sample_vector.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/pickle.h"
@@ -25,15 +26,12 @@
 #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,
+                            std::string* histogram_name,
                             int* flags,
                             int* declared_min,
                             int* declared_max,
@@ -84,7 +82,7 @@
 // static
 const size_t Histogram::kBucketCount_MAX = 16384u;
 
-HistogramBase* Histogram::FactoryGet(const string& name,
+HistogramBase* Histogram::FactoryGet(const std::string& name,
                                      Sample minimum,
                                      Sample maximum,
                                      size_t bucket_count,
@@ -123,7 +121,7 @@
   return histogram;
 }
 
-HistogramBase* Histogram::FactoryTimeGet(const string& name,
+HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
                                          TimeDelta minimum,
                                          TimeDelta maximum,
                                          size_t bucket_count,
@@ -133,6 +131,23 @@
                     flags);
 }
 
+HistogramBase* Histogram::FactoryGet(const char* name,
+                                     Sample minimum,
+                                     Sample maximum,
+                                     size_t bucket_count,
+                                     int32 flags) {
+  return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
+}
+
+HistogramBase* Histogram::FactoryTimeGet(const char* name,
+                                         TimeDelta minimum,
+                                         TimeDelta maximum,
+                                         size_t bucket_count,
+                                         int32 flags) {
+  return FactoryTimeGet(std::string(name), minimum, maximum, 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
@@ -216,7 +231,7 @@
 }
 
 // static
-bool Histogram::InspectConstructionArguments(const string& name,
+bool Histogram::InspectConstructionArguments(const std::string& name,
                                              Sample* minimum,
                                              Sample* maximum,
                                              size_t* bucket_count) {
@@ -257,6 +272,10 @@
 }
 
 void Histogram::Add(int value) {
+  AddCount(value, 1);
+}
+
+void Histogram::AddCount(int value, int count) {
   DCHECK_EQ(0, ranges(0));
   DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
 
@@ -264,11 +283,17 @@
     value = kSampleType_MAX - 1;
   if (value < 0)
     value = 0;
-  samples_->Accumulate(value, 1);
+  if (count <= 0) {
+    NOTREACHED();
+    return;
+  }
+  samples_->Accumulate(value, count);
+
+  FindAndRunCallback(value);
 }
 
 scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
-  return SnapshotSampleVector().Pass();
+  return SnapshotSampleVector();
 }
 
 void Histogram::AddSamples(const HistogramSamples& samples) {
@@ -280,14 +305,14 @@
 }
 
 // The following methods provide a graphical histogram display.
-void Histogram::WriteHTMLGraph(string* output) const {
+void Histogram::WriteHTMLGraph(std::string* output) const {
   // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
   output->append("<PRE>");
   WriteAsciiImpl(true, "<br>", output);
   output->append("</PRE>");
 }
 
-void Histogram::WriteAscii(string* output) const {
+void Histogram::WriteAscii(std::string* output) const {
   WriteAsciiImpl(true, "\n", output);
 }
 
@@ -301,7 +326,7 @@
       pickle->WriteUInt32(bucket_ranges()->checksum());
 }
 
-Histogram::Histogram(const string& name,
+Histogram::Histogram(const std::string& name,
                      Sample minimum,
                      Sample maximum,
                      const BucketRanges* ranges)
@@ -334,7 +359,7 @@
   return current/denominator;
 }
 
-const string Histogram::GetAsciiBucketRange(size_t i) const {
+const std::string Histogram::GetAsciiBucketRange(size_t i) const {
   return GetSimpleAsciiBucketRange(ranges(i));
 }
 
@@ -343,7 +368,7 @@
 
 // static
 HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
-  string histogram_name;
+  std::string histogram_name;
   int flags;
   int declared_min;
   int declared_max;
@@ -369,12 +394,12 @@
 scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
   scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
   samples->Add(*samples_);
-  return samples.Pass();
+  return samples;
 }
 
 void Histogram::WriteAsciiImpl(bool graph_it,
-                               const string& newline,
-                               string* output) const {
+                               const std::string& newline,
+                               std::string* output) const {
   // Get local (stack) copies of all effectively volatile class data so that we
   // are consistent across our output activities.
   scoped_ptr<SampleVector> snapshot = SnapshotSampleVector();
@@ -415,7 +440,7 @@
     if (!current && !PrintEmptyBucket(i))
       continue;
     remaining -= current;
-    string range = GetAsciiBucketRange(i);
+    std::string range = GetAsciiBucketRange(i);
     output->append(range);
     for (size_t j = 0; range.size() + j < print_width + 1; ++j)
       output->push_back(' ');
@@ -451,7 +476,7 @@
 
 void Histogram::WriteAsciiHeader(const SampleVector& samples,
                                  Count sample_count,
-                                 string* output) const {
+                                 std::string* output) const {
   StringAppendF(output,
                 "Histogram: %s recorded %d samples",
                 histogram_name().c_str(),
@@ -471,7 +496,7 @@
                                         const Count current,
                                         const int64 remaining,
                                         const size_t i,
-                                        string* output) const {
+                                        std::string* output) const {
   double scaled_sum = (past + current + remaining) / 100.0;
   WriteAsciiBucketValue(current, scaled_sum, output);
   if (0 < i) {
@@ -515,7 +540,7 @@
 
 LinearHistogram::~LinearHistogram() {}
 
-HistogramBase* LinearHistogram::FactoryGet(const string& name,
+HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
                                            Sample minimum,
                                            Sample maximum,
                                            size_t bucket_count,
@@ -524,7 +549,7 @@
       name, minimum, maximum, bucket_count, flags, NULL);
 }
 
-HistogramBase* LinearHistogram::FactoryTimeGet(const string& name,
+HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
                                                TimeDelta minimum,
                                                TimeDelta maximum,
                                                size_t bucket_count,
@@ -534,6 +559,23 @@
                     flags);
 }
 
+HistogramBase* LinearHistogram::FactoryGet(const char* name,
+                                           Sample minimum,
+                                           Sample maximum,
+                                           size_t bucket_count,
+                                           int32 flags) {
+  return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
+}
+
+HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
+                                               TimeDelta minimum,
+                                               TimeDelta maximum,
+                                               size_t bucket_count,
+                                               int32 flags) {
+  return FactoryTimeGet(std::string(name),  minimum, maximum, bucket_count,
+                        flags);
+}
+
 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
       const std::string& name,
       Sample minimum,
@@ -587,7 +629,7 @@
   return LINEAR_HISTOGRAM;
 }
 
-LinearHistogram::LinearHistogram(const string& name,
+LinearHistogram::LinearHistogram(const std::string& name,
                                  Sample minimum,
                                  Sample maximum,
                                  const BucketRanges* ranges)
@@ -602,7 +644,7 @@
   return current/denominator;
 }
 
-const string LinearHistogram::GetAsciiBucketRange(size_t i) const {
+const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
   int range = ranges(i);
   BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
   if (it == bucket_description_.end())
@@ -632,7 +674,7 @@
 
 // static
 HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
-  string histogram_name;
+  std::string histogram_name;
   int flags;
   int declared_min;
   int declared_max;
@@ -657,7 +699,8 @@
 // This section provides implementation for BooleanHistogram.
 //------------------------------------------------------------------------------
 
-HistogramBase* BooleanHistogram::FactoryGet(const string& name, int32 flags) {
+HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
+                                            int32 flags) {
   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
   if (!histogram) {
     // To avoid racy destruction at shutdown, the following will be leaked.
@@ -678,16 +721,20 @@
   return histogram;
 }
 
+HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) {
+  return FactoryGet(std::string(name), flags);
+}
+
 HistogramType BooleanHistogram::GetHistogramType() const {
   return BOOLEAN_HISTOGRAM;
 }
 
-BooleanHistogram::BooleanHistogram(const string& name,
+BooleanHistogram::BooleanHistogram(const std::string& name,
                                    const BucketRanges* ranges)
     : LinearHistogram(name, 1, 2, ranges) {}
 
 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
-  string histogram_name;
+  std::string histogram_name;
   int flags;
   int declared_min;
   int declared_max;
@@ -712,9 +759,10 @@
 // CustomHistogram:
 //------------------------------------------------------------------------------
 
-HistogramBase* CustomHistogram::FactoryGet(const string& name,
-                                           const vector<Sample>& custom_ranges,
-                                           int32 flags) {
+HistogramBase* CustomHistogram::FactoryGet(
+    const std::string& name,
+    const std::vector<Sample>& custom_ranges,
+    int32 flags) {
   CHECK(ValidateCustomRanges(custom_ranges));
 
   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
@@ -737,14 +785,21 @@
   return histogram;
 }
 
+HistogramBase* CustomHistogram::FactoryGet(
+    const char* name,
+    const std::vector<Sample>& custom_ranges,
+    int32 flags) {
+  return FactoryGet(std::string(name), custom_ranges, flags);
+}
+
 HistogramType CustomHistogram::GetHistogramType() const {
   return CUSTOM_HISTOGRAM;
 }
 
 // static
-vector<Sample> CustomHistogram::ArrayToCustomRanges(
+std::vector<Sample> CustomHistogram::ArrayToCustomRanges(
     const Sample* values, size_t num_values) {
-  vector<Sample> all_values;
+  std::vector<Sample> all_values;
   for (size_t i = 0; i < num_values; ++i) {
     Sample value = values[i];
     all_values.push_back(value);
@@ -756,7 +811,7 @@
   return all_values;
 }
 
-CustomHistogram::CustomHistogram(const string& name,
+CustomHistogram::CustomHistogram(const std::string& name,
                                  const BucketRanges* ranges)
     : Histogram(name,
                 ranges->range(1),
@@ -782,7 +837,7 @@
 
 // static
 HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
-  string histogram_name;
+  std::string histogram_name;
   int flags;
   int declared_min;
   int declared_max;
@@ -795,7 +850,7 @@
   }
 
   // First and last ranges are not serialized.
-  vector<Sample> sample_ranges(bucket_count - 1);
+  std::vector<Sample> sample_ranges(bucket_count - 1);
 
   for (size_t i = 0; i < sample_ranges.size(); ++i) {
     if (!iter->ReadInt(&sample_ranges[i]))
@@ -813,7 +868,7 @@
 
 // static
 bool CustomHistogram::ValidateCustomRanges(
-    const vector<Sample>& custom_ranges) {
+    const std::vector<Sample>& custom_ranges) {
   bool has_valid_range = false;
   for (size_t i = 0; i < custom_ranges.size(); i++) {
     Sample sample = custom_ranges[i];
@@ -827,9 +882,9 @@
 
 // static
 BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges(
-      const vector<Sample>& custom_ranges) {
+      const std::vector<Sample>& custom_ranges) {
   // Remove the duplicates in the custom ranges array.
-  vector<int> ranges = custom_ranges;
+  std::vector<int> ranges = custom_ranges;
   ranges.push_back(0);  // Ensure we have a zero value.
   ranges.push_back(HistogramBase::kSampleType_MAX);
   std::sort(ranges.begin(), ranges.end());
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 9ee172e..15e0ec2 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -83,15 +83,14 @@
 #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 Pickle;
+class PickleIterator;
 class SampleVector;
 
 class BASE_EXPORT Histogram : public HistogramBase {
@@ -122,6 +121,20 @@
                                        size_t bucket_count,
                                        int32 flags);
 
+  // Overloads of the above two functions that take a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+  static HistogramBase* FactoryTimeGet(const char* name,
+                                       base::TimeDelta minimum,
+                                       base::TimeDelta maximum,
+                                       size_t bucket_count,
+                                       int32 flags);
+
   static void InitializeBucketRanges(Sample minimum,
                                      Sample maximum,
                                      BucketRanges* ranges);
@@ -168,9 +181,10 @@
                                 Sample expected_maximum,
                                 size_t expected_bucket_count) const override;
   void Add(Sample value) override;
+  void AddCount(Sample value, int count) override;
   scoped_ptr<HistogramSamples> SnapshotSamples() const override;
   void AddSamples(const HistogramSamples& samples) override;
-  bool AddSamplesFromPickle(PickleIterator* iter) override;
+  bool AddSamplesFromPickle(base::PickleIterator* iter) override;
   void WriteHTMLGraph(std::string* output) const override;
   void WriteAscii(std::string* output) const override;
 
@@ -185,7 +199,7 @@
   ~Histogram() override;
 
   // HistogramBase implementation:
-  bool SerializeInfoImpl(Pickle* pickle) const override;
+  bool SerializeInfoImpl(base::Pickle* pickle) const override;
 
   // Method to override to skip the display of the i'th bucket if it's empty.
   virtual bool PrintEmptyBucket(size_t index) const;
@@ -205,13 +219,14 @@
   FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptBucketBounds);
   FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
   FRIEND_TEST_ALL_PREFIXES(HistogramTest, NameMatchTest);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, AddCountTest);
 
   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);
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
   // Implementation of SnapshotSamples function.
   scoped_ptr<SampleVector> SnapshotSampleVector() const;
@@ -278,6 +293,20 @@
                                        size_t bucket_count,
                                        int32 flags);
 
+  // Overloads of the above two functions that take a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+  static HistogramBase* FactoryTimeGet(const char* 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.
@@ -320,9 +349,9 @@
   bool PrintEmptyBucket(size_t index) const override;
 
  private:
-  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
-      PickleIterator* iter);
-  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
   // For some ranges, we store a printable description of a bucket range.
   // If there is no description, then GetAsciiBucketRange() uses parent class
@@ -340,14 +369,19 @@
  public:
   static HistogramBase* FactoryGet(const std::string& name, int32 flags);
 
+  // Overload of the above function that takes a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name, int32 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);
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
   DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
 };
@@ -365,6 +399,13 @@
                                    const std::vector<Sample>& custom_ranges,
                                    int32 flags);
 
+  // Overload of the above function that takes a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name,
+                                   const std::vector<Sample>& custom_ranges,
+                                   int32 flags);
+
   // Overridden from Histogram:
   HistogramType GetHistogramType() const override;
 
@@ -381,14 +422,14 @@
                   const BucketRanges* ranges);
 
   // HistogramBase implementation:
-  bool SerializeInfoImpl(Pickle* pickle) const override;
+  bool SerializeInfoImpl(base::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);
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
   static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges);
   static BucketRanges* CreateBucketRangesFromCustomRanges(
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
index de34c79..e9d4898 100644
--- a/base/metrics/histogram_base.cc
+++ b/base/metrics/histogram_base.cc
@@ -5,6 +5,7 @@
 #include "base/metrics/histogram_base.h"
 
 #include <climits>
+#include <utility>
 
 #include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
@@ -12,6 +13,7 @@
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/pickle.h"
 #include "base/process/process_handle.h"
 #include "base/strings/stringprintf.h"
@@ -71,11 +73,13 @@
 }
 
 void HistogramBase::SetFlags(int32 flags) {
-  flags_ |= flags;
+  HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
+  subtle::NoBarrier_Store(&flags_, old_flags | flags);
 }
 
 void HistogramBase::ClearFlags(int32 flags) {
-  flags_ &= ~flags;
+  HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
+  subtle::NoBarrier_Store(&flags_, old_flags & ~flags);
 }
 
 void HistogramBase::AddTime(const TimeDelta& time) {
@@ -111,12 +115,22 @@
   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.Set("params", std::move(parameters));
+  root.Set("buckets", std::move(buckets));
   root.SetInteger("pid", GetCurrentProcId());
   serializer.Serialize(root);
 }
 
+void HistogramBase::FindAndRunCallback(HistogramBase::Sample sample) const {
+  if ((flags() & kCallbackExists) == 0)
+    return;
+
+  StatisticsRecorder::OnSampleCallback cb =
+      StatisticsRecorder::FindCallback(histogram_name());
+  if (!cb.is_null())
+    cb.Run(sample);
+}
+
 void HistogramBase::WriteAsciiBucketGraph(double current_size,
                                           double max_size,
                                           std::string* output) const {
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
index c24df24..d246691 100644
--- a/base/metrics/histogram_base.h
+++ b/base/metrics/histogram_base.h
@@ -17,22 +17,21 @@
 #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;
+class Pickle;
+class PickleIterator;
 
 ////////////////////////////////////////////////////////////////////////////////
 // These enums are used to facilitate deserialization of histograms from other
 // processes into the browser. If you create another class that inherits from
 // HistogramBase, add new histogram types and names below.
 
-enum BASE_EXPORT HistogramType {
+enum HistogramType {
   HISTOGRAM,
   LINEAR_HISTOGRAM,
   BOOLEAN_HISTOGRAM,
@@ -44,8 +43,7 @@
 
 // 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);
+BASE_EXPORT HistogramBase* DeserializeHistogramInfo(base::PickleIterator* iter);
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -75,6 +73,12 @@
     // the source histogram!).
     kIPCSerializationSourceFlag = 0x10,
 
+    // Indicates that a callback exists for when a new sample is recorded on
+    // this histogram. We store this as a flag with the histogram since
+    // histograms can be in performance critical code, and this allows us
+    // to shortcut looking up the callback if it doesn't exist.
+    kCallbackExists = 0x20,
+
     // Only for Histogram and its sub classes: fancy bucket-naming support.
     kHexRangePrintingFlag = 0x8000,
   };
@@ -93,7 +97,7 @@
   explicit HistogramBase(const std::string& name);
   virtual ~HistogramBase();
 
-  std::string histogram_name() const { return histogram_name_; }
+  const std::string& histogram_name() const { return histogram_name_; }
 
   // Comapres |name| to the histogram name and triggers a DCHECK if they do not
   // match. This is a helper function used by histogram macros, which results in
@@ -101,7 +105,7 @@
   void CheckName(const StringPiece& name) const;
 
   // Operations with Flags enum.
-  int32_t flags() const { return flags_; }
+  int32_t flags() const { return subtle::NoBarrier_Load(&flags_); }
   void SetFlags(int32_t flags);
   void ClearFlags(int32_t flags);
 
@@ -116,17 +120,23 @@
 
   virtual void Add(Sample value) = 0;
 
+  // In Add function the |value| bucket is increased by one, but in some use
+  // cases we need to increase this value by an arbitrary integer. AddCount
+  // function increases the |value| bucket by |count|. |count| should be greater
+  // than or equal to 1.
+  virtual void AddCount(Sample value, int count) = 0;
+
   // 2 convenient functions that call Add(Sample).
   void AddTime(const TimeDelta& time);
   void AddBoolean(bool value);
 
   virtual void AddSamples(const HistogramSamples& samples) = 0;
-  virtual bool AddSamplesFromPickle(PickleIterator* iter) = 0;
+  virtual bool AddSamplesFromPickle(base::PickleIterator* iter) = 0;
 
   // Serialize the histogram info into |pickle|.
   // Note: This only serializes the construction arguments of the histogram, but
   // does not serialize the samples.
-  bool SerializeInfo(Pickle* pickle) const;
+  bool SerializeInfo(base::Pickle* pickle) const;
 
   // Try to find out data corruption from histogram and the samples.
   // The returned value is a combination of Inconsistency enum.
@@ -147,7 +157,7 @@
 
  protected:
   // Subclasses should implement this function to make SerializeInfo work.
-  virtual bool SerializeInfoImpl(Pickle* pickle) const = 0;
+  virtual bool SerializeInfoImpl(base::Pickle* pickle) const = 0;
 
   // Writes information about the construction parameters in |params|.
   virtual void GetParameters(DictionaryValue* params) const = 0;
@@ -173,9 +183,13 @@
                              double scaled_sum,
                              std::string* output) const;
 
+  // Retrieves the callback for this histogram, if one exists, and runs it
+  // passing |sample| as the parameter.
+  void FindAndRunCallback(Sample sample) const;
+
  private:
   const std::string histogram_name_;
-  int32_t flags_;
+  AtomicCount flags_;
 
   DISALLOW_COPY_AND_ASSIGN(HistogramBase);
 };
diff --git a/base/metrics/histogram_delta_serialization.cc b/base/metrics/histogram_delta_serialization.cc
index e4aad13..f2b825b 100644
--- a/base/metrics/histogram_delta_serialization.cc
+++ b/base/metrics/histogram_delta_serialization.cc
@@ -61,6 +61,8 @@
 
 void HistogramDeltaSerialization::PrepareAndSerializeDeltas(
     std::vector<std::string>* serialized_deltas) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
   serialized_deltas_ = serialized_deltas;
   // Note: Before serializing, we set the kIPCSerializationSourceFlag for all
   // the histograms, so that the receiving process can distinguish them from the
@@ -84,6 +86,7 @@
 void HistogramDeltaSerialization::RecordDelta(
     const HistogramBase& histogram,
     const HistogramSamples& snapshot) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_NE(0, snapshot.TotalCount());
 
   Pickle pickle;
@@ -95,16 +98,22 @@
 
 void HistogramDeltaSerialization::InconsistencyDetected(
     HistogramBase::Inconsistency problem) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
   inconsistencies_histogram_->Add(problem);
 }
 
 void HistogramDeltaSerialization::UniqueInconsistencyDetected(
     HistogramBase::Inconsistency problem) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
   inconsistencies_unique_histogram_->Add(problem);
 }
 
 void HistogramDeltaSerialization::InconsistencyDetectedInLoggedCount(
     int amount) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
   inconsistent_snapshot_histogram_->Add(std::abs(amount));
 }
 
diff --git a/base/metrics/histogram_delta_serialization.h b/base/metrics/histogram_delta_serialization.h
index a379914..0bc4a59 100644
--- a/base/metrics/histogram_delta_serialization.h
+++ b/base/metrics/histogram_delta_serialization.h
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram_flattener.h"
 #include "base/metrics/histogram_snapshot_manager.h"
+#include "base/threading/thread_checker.h"
 
 namespace base {
 
@@ -45,6 +46,8 @@
       HistogramBase::Inconsistency problem) override;
   void InconsistencyDetectedInLoggedCount(int amount) override;
 
+  ThreadChecker thread_checker_;
+
   // Calculates deltas in histogram counters.
   HistogramSnapshotManager histogram_snapshot_manager_;
 
diff --git a/base/metrics/histogram_macros.h b/base/metrics/histogram_macros.h
index 2aee1a5..882c58a 100644
--- a/base/metrics/histogram_macros.h
+++ b/base/metrics/histogram_macros.h
@@ -189,6 +189,9 @@
 #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
     name, sample, 1, 100, 50)
 
+#define UMA_HISTOGRAM_COUNTS_1000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000, 50)
+
 #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
     name, sample, 1, 10000, 50)
 
@@ -203,6 +206,9 @@
 #define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
     name, sample, 1, 1000, 50)
 
+#define UMA_HISTOGRAM_MEMORY_LARGE_MB(name, sample) \
+    UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 64000, 100)
+
 #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
     UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
 
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h
index c4c0a98..54185cf 100644
--- a/base/metrics/histogram_samples.h
+++ b/base/metrics/histogram_samples.h
@@ -9,11 +9,10 @@
 #include "base/metrics/histogram_base.h"
 #include "base/memory/scoped_ptr.h"
 
-class Pickle;
-class PickleIterator;
-
 namespace base {
 
+class Pickle;
+class PickleIterator;
 class SampleCountIterator;
 
 // HistogramSamples is a container storing all samples of a histogram.
diff --git a/base/metrics/histogram_snapshot_manager.cc b/base/metrics/histogram_snapshot_manager.cc
index b1e26da..a7605aa 100644
--- a/base/metrics/histogram_snapshot_manager.cc
+++ b/base/metrics/histogram_snapshot_manager.cc
@@ -10,9 +10,6 @@
 #include "base/metrics/statistics_recorder.h"
 #include "base/stl_util.h"
 
-using std::map;
-using std::string;
-
 namespace base {
 
 HistogramSnapshotManager::HistogramSnapshotManager(
@@ -78,7 +75,7 @@
   }
 
   HistogramSamples* to_log;
-  map<string, HistogramSamples*>::iterator it =
+  std::map<std::string, HistogramSamples*>::iterator it =
       logged_samples_.find(histogram_name);
   if (it == logged_samples_.end()) {
     to_log = snapshot.release();
diff --git a/base/metrics/histogram_snapshot_manager_unittest.cc b/base/metrics/histogram_snapshot_manager_unittest.cc
index 3a1fd40..e9e7398 100644
--- a/base/metrics/histogram_snapshot_manager_unittest.cc
+++ b/base/metrics/histogram_snapshot_manager_unittest.cc
@@ -7,8 +7,8 @@
 #include <string>
 #include <vector>
 
-#include "base/metrics/histogram.h"
 #include "base/metrics/histogram_delta_serialization.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/statistics_recorder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index df43e65..b144379 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -2,7 +2,7 @@
 // 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 "base/metrics/histogram.h"
 
 #include <climits>
 #include <algorithm>
@@ -11,15 +11,13 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/bucket_ranges.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.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 {
@@ -55,7 +53,7 @@
       "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
   EXPECT_TRUE(linear_histogram);
 
-  vector<int> custom_ranges;
+  std::vector<int> custom_ranges;
   custom_ranges.push_back(1);
   custom_ranges.push_back(5);
   HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
@@ -157,7 +155,7 @@
 
 TEST_F(HistogramTest, ArrayToCustomRangesTest) {
   const HistogramBase::Sample ranges[3] = {5, 10, 20};
-  vector<HistogramBase::Sample> ranges_vec =
+  std::vector<HistogramBase::Sample> ranges_vec =
       CustomHistogram::ArrayToCustomRanges(ranges, 3);
   ASSERT_EQ(6u, ranges_vec.size());
   EXPECT_EQ(5, ranges_vec[0]);
@@ -170,7 +168,7 @@
 
 TEST_F(HistogramTest, CustomHistogramTest) {
   // A well prepared custom ranges.
-  vector<HistogramBase::Sample> custom_ranges;
+  std::vector<HistogramBase::Sample> custom_ranges;
   custom_ranges.push_back(1);
   custom_ranges.push_back(2);
 
@@ -220,7 +218,7 @@
   // We should probably change the restriction on the base class (or not inherit
   // the base class!).
 
-  vector<HistogramBase::Sample> custom_ranges;
+  std::vector<HistogramBase::Sample> custom_ranges;
   custom_ranges.push_back(4);
 
   Histogram* histogram = static_cast<Histogram*>(
@@ -233,6 +231,30 @@
   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
 }
 
+// Test the AddCount function.
+TEST_F(HistogramTest, AddCountTest) {
+  const size_t kBucketCount = 50;
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("AddCountHistogram", 10, 100, kBucketCount,
+                            HistogramBase::kNoFlags));
+
+  histogram->AddCount(20, 15);
+  histogram->AddCount(30, 14);
+
+  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+  EXPECT_EQ(29, samples->TotalCount());
+  EXPECT_EQ(15, samples->GetCount(20));
+  EXPECT_EQ(14, samples->GetCount(30));
+
+  histogram->AddCount(20, 25);
+  histogram->AddCount(30, 24);
+
+  scoped_ptr<SampleVector> samples2 = histogram->SnapshotSampleVector();
+  EXPECT_EQ(78, samples2->TotalCount());
+  EXPECT_EQ(40, samples2->GetCount(20));
+  EXPECT_EQ(38, samples2->GetCount(30));
+}
+
 // Make sure histogram handles out-of-bounds data gracefully.
 TEST_F(HistogramTest, BoundsTest) {
   const size_t kBucketCount = 50;
@@ -256,7 +278,7 @@
   EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2));
   EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1));
 
-  vector<int> custom_ranges;
+  std::vector<int> custom_ranges;
   custom_ranges.push_back(10);
   custom_ranges.push_back(50);
   custom_ranges.push_back(100);
@@ -405,7 +427,7 @@
 }
 
 TEST_F(HistogramTest, CustomHistogramSerializeInfo) {
-  vector<int> custom_ranges;
+  std::vector<int> custom_ranges;
   custom_ranges.push_back(10);
   custom_ranges.push_back(100);
 
@@ -484,7 +506,7 @@
       linear_histogram->HasConstructionArguments(
           1, HistogramBase::kSampleType_MAX - 1, 8));
 
-  vector<int> custom_ranges;
+  std::vector<int> custom_ranges;
   custom_ranges.push_back(0);
   custom_ranges.push_back(5);
   Histogram* custom_histogram = static_cast<Histogram*>(
diff --git a/base/metrics/metrics_hashes.cc b/base/metrics/metrics_hashes.cc
new file mode 100644
index 0000000..b09ea4b
--- /dev/null
+++ b/base/metrics/metrics_hashes.cc
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/metrics_hashes.h"
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "base/sys_byteorder.h"
+
+namespace base {
+
+namespace {
+
+// Converts the 8-byte prefix of an MD5 hash into a uint64 value.
+inline uint64_t DigestToUInt64(const base::MD5Digest& digest) {
+  uint64_t value;
+  DCHECK_GE(sizeof(digest.a), sizeof(value));
+  memcpy(&value, digest.a, sizeof(value));
+  return base::NetToHost64(value);
+}
+
+}  // namespace
+
+uint64_t HashMetricName(const std::string& name) {
+  base::MD5Digest digest;
+  base::MD5Sum(name.c_str(), name.size(), &digest);
+  return DigestToUInt64(digest);
+}
+
+}  // namespace metrics
diff --git a/base/metrics/metrics_hashes.h b/base/metrics/metrics_hashes.h
new file mode 100644
index 0000000..ff1c800
--- /dev/null
+++ b/base/metrics/metrics_hashes.h
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_METRICS_HASHES_H_
+#define BASE_METRICS_METRICS_HASHES_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Computes a uint64 hash of a given string based on its MD5 hash. Suitable for
+// metric names.
+BASE_EXPORT uint64_t HashMetricName(const std::string& name);
+
+}  // namespace metrics
+
+#endif  // BASE_METRICS_METRICS_HASHES_H_
diff --git a/base/metrics/metrics_hashes_unittest.cc b/base/metrics/metrics_hashes_unittest.cc
new file mode 100644
index 0000000..cfe3625
--- /dev/null
+++ b/base/metrics/metrics_hashes_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/metrics_hashes.h"
+
+#include "base/format_macros.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Make sure our ID hashes are the same as what we see on the server side.
+TEST(MetricsUtilTest, HashMetricName) {
+  static const struct {
+    std::string input;
+    std::string output;
+  } cases[] = {
+    {"Back", "0x0557fa923dcee4d0"},
+    {"Forward", "0x67d2f6740a8eaebf"},
+    {"NewTab", "0x290eb683f96572f1"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint64_t hash = HashMetricName(cases[i].input);
+    std::string hash_hex = base::StringPrintf("0x%016" PRIx64, hash);
+    EXPECT_EQ(cases[i].output, hash_hex);
+  }
+}
+
+}  // namespace metrics
diff --git a/base/metrics/sample_map.cc b/base/metrics/sample_map.cc
index 42468cb..f2540a4 100644
--- a/base/metrics/sample_map.cc
+++ b/base/metrics/sample_map.cc
@@ -6,8 +6,6 @@
 
 #include "base/logging.h"
 
-using std::map;
-
 namespace base {
 
 typedef HistogramBase::Count Count;
@@ -24,7 +22,7 @@
 }
 
 Count SampleMap::GetCount(Sample value) const {
-  map<Sample, Count>::const_iterator it = sample_counts_.find(value);
+  std::map<Sample, Count>::const_iterator it = sample_counts_.find(value);
   if (it == sample_counts_.end())
     return 0;
   return it->second;
@@ -32,10 +30,8 @@
 
 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;
+  for (const auto& entry : sample_counts_) {
+    count += entry.second;
   }
   return count;
 }
@@ -53,14 +49,17 @@
     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;
+
+    sample_counts_[min] += (op == HistogramSamples::ADD) ? count : -count;
   }
   return true;
 }
 
 SampleMapIterator::SampleMapIterator(const SampleToCountMap& sample_counts)
     : iter_(sample_counts.begin()),
-      end_(sample_counts.end()) {}
+      end_(sample_counts.end()) {
+  SkipEmptyBuckets();
+}
 
 SampleMapIterator::~SampleMapIterator() {}
 
@@ -70,7 +69,8 @@
 
 void SampleMapIterator::Next() {
   DCHECK(!Done());
-  iter_++;
+  ++iter_;
+  SkipEmptyBuckets();
 }
 
 void SampleMapIterator::Get(Sample* min, Sample* max, Count* count) const {
@@ -83,4 +83,10 @@
     *count = iter_->second;
 }
 
+void SampleMapIterator::SkipEmptyBuckets() {
+  while (!Done() && iter_->second == 0) {
+    ++iter_;
+  }
+}
+
 }  // namespace base
diff --git a/base/metrics/sample_map.h b/base/metrics/sample_map.h
index 7a780ea..d1d7cd6 100644
--- a/base/metrics/sample_map.h
+++ b/base/metrics/sample_map.h
@@ -17,7 +17,7 @@
 
 namespace base {
 
-class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples {
+class BASE_EXPORT SampleMap : public HistogramSamples {
  public:
   SampleMap();
   ~SampleMap() override;
@@ -40,7 +40,7 @@
   DISALLOW_COPY_AND_ASSIGN(SampleMap);
 };
 
-class BASE_EXPORT_PRIVATE SampleMapIterator : public SampleCountIterator {
+class BASE_EXPORT SampleMapIterator : public SampleCountIterator {
  public:
   typedef std::map<HistogramBase::Sample, HistogramBase::Count>
       SampleToCountMap;
@@ -56,6 +56,8 @@
            HistogramBase::Count* count) const override;
 
  private:
+  void SkipEmptyBuckets();
+
   SampleToCountMap::const_iterator iter_;
   const SampleToCountMap::const_iterator end_;
 };
diff --git a/base/metrics/sample_map_unittest.cc b/base/metrics/sample_map_unittest.cc
index 1a53ee7..22ce8e1 100644
--- a/base/metrics/sample_map_unittest.cc
+++ b/base/metrics/sample_map_unittest.cc
@@ -2,8 +2,9 @@
 // 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 "base/memory/scoped_ptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -86,10 +87,43 @@
   EXPECT_EQ(-300, count);
 
   it->Next();
+  EXPECT_TRUE(it->Done());
+}
+
+TEST(SampleMapIteratorTest, SkipEmptyRanges) {
+  SampleMap samples;
+  samples.Accumulate(5, 1);
+  samples.Accumulate(10, 2);
+  samples.Accumulate(15, 3);
+  samples.Accumulate(20, 4);
+  samples.Accumulate(25, 5);
+
+  SampleMap samples2;
+  samples2.Accumulate(5, 1);
+  samples2.Accumulate(20, 4);
+  samples2.Accumulate(25, 5);
+
+  samples.Subtract(samples2);
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+  EXPECT_FALSE(it->Done());
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+
   it->Get(&min, &max, &count);
-  EXPECT_EQ(5, min);
-  EXPECT_EQ(6, max);
-  EXPECT_EQ(0, count);
+  EXPECT_EQ(10, min);
+  EXPECT_EQ(11, max);
+  EXPECT_EQ(2, count);
+
+  it->Next();
+  EXPECT_FALSE(it->Done());
+
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(15, min);
+  EXPECT_EQ(16, max);
+  EXPECT_EQ(3, count);
 
   it->Next();
   EXPECT_TRUE(it->Done());
diff --git a/base/metrics/sample_vector.cc b/base/metrics/sample_vector.cc
index ca3205e..1202527 100644
--- a/base/metrics/sample_vector.cc
+++ b/base/metrics/sample_vector.cc
@@ -7,8 +7,6 @@
 #include "base/logging.h"
 #include "base/metrics/bucket_ranges.h"
 
-using std::vector;
-
 namespace base {
 
 typedef HistogramBase::Count Count;
@@ -111,7 +109,7 @@
   return mid;
 }
 
-SampleVectorIterator::SampleVectorIterator(const vector<Count>* counts,
+SampleVectorIterator::SampleVectorIterator(const std::vector<Count>* counts,
                                            const BucketRanges* bucket_ranges)
     : counts_(counts),
       bucket_ranges_(bucket_ranges),
diff --git a/base/metrics/sample_vector.h b/base/metrics/sample_vector.h
index 55f9b96..8cb2ab9 100644
--- a/base/metrics/sample_vector.h
+++ b/base/metrics/sample_vector.h
@@ -20,7 +20,7 @@
 
 class BucketRanges;
 
-class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
+class BASE_EXPORT SampleVector : public HistogramSamples {
  public:
   explicit SampleVector(const BucketRanges* bucket_ranges);
   ~SampleVector() override;
@@ -53,7 +53,7 @@
   DISALLOW_COPY_AND_ASSIGN(SampleVector);
 };
 
-class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator {
+class BASE_EXPORT SampleVectorIterator : public SampleCountIterator {
  public:
   SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
                        const BucketRanges* bucket_ranges);
diff --git a/base/metrics/sample_vector_unittest.cc b/base/metrics/sample_vector_unittest.cc
index 9c7ba96..fd42376 100644
--- a/base/metrics/sample_vector_unittest.cc
+++ b/base/metrics/sample_vector_unittest.cc
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/metrics/sample_vector.h"
+
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/bucket_ranges.h"
 #include "base/metrics/histogram.h"
-#include "base/metrics/sample_vector.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using std::vector;
-
 namespace base {
 namespace {
 
@@ -179,7 +178,7 @@
   ranges.set_range(3, 3);
   ranges.set_range(4, 4);
 
-  vector<HistogramBase::Count> counts(3);
+  std::vector<HistogramBase::Count> counts(3);
   counts[0] = 1;
   counts[1] = 0;  // Iterator will bypass this empty bucket.
   counts[2] = 2;
diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
index 773eeb6..7955c57 100644
--- a/base/metrics/sparse_histogram.cc
+++ b/base/metrics/sparse_histogram.cc
@@ -4,22 +4,22 @@
 
 #include "base/metrics/sparse_histogram.h"
 
+#include <utility>
+
 #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* SparseHistogram::FactoryGet(const std::string& name,
+                                           int32 flags) {
   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
 
   if (!histogram) {
@@ -48,8 +48,20 @@
 }
 
 void SparseHistogram::Add(Sample value) {
-  base::AutoLock auto_lock(lock_);
-  samples_.Accumulate(value, 1);
+  AddCount(value, 1);
+}
+
+void SparseHistogram::AddCount(Sample value, int count) {
+  if (count <= 0) {
+    NOTREACHED();
+    return;
+  }
+  {
+    base::AutoLock auto_lock(lock_);
+    samples_.Accumulate(value, count);
+  }
+
+  FindAndRunCallback(value);
 }
 
 scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
@@ -57,7 +69,7 @@
 
   base::AutoLock auto_lock(lock_);
   snapshot->Add(samples_);
-  return snapshot.Pass();
+  return std::move(snapshot);
 }
 
 void SparseHistogram::AddSamples(const HistogramSamples& samples) {
@@ -70,13 +82,13 @@
   return samples_.AddFromPickle(iter);
 }
 
-void SparseHistogram::WriteHTMLGraph(string* output) const {
+void SparseHistogram::WriteHTMLGraph(std::string* output) const {
   output->append("<PRE>");
   WriteAsciiImpl(true, "<br>", output);
   output->append("</PRE>");
 }
 
-void SparseHistogram::WriteAscii(string* output) const {
+void SparseHistogram::WriteAscii(std::string* output) const {
   WriteAsciiImpl(true, "\n", output);
 }
 
@@ -84,11 +96,11 @@
   return pickle->WriteString(histogram_name()) && pickle->WriteInt(flags());
 }
 
-SparseHistogram::SparseHistogram(const string& name)
+SparseHistogram::SparseHistogram(const std::string& name)
     : HistogramBase(name) {}
 
 HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
-  string histogram_name;
+  std::string histogram_name;
   int flags;
   if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
     DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
@@ -129,8 +141,7 @@
   Count largest_count = 0;
   Sample largest_sample = 0;
   scoped_ptr<SampleCountIterator> it = snapshot->Iterator();
-  while (!it->Done())
-  {
+  while (!it->Done()) {
     Sample min;
     Sample max;
     Count count;
@@ -145,15 +156,14 @@
 
   // iterate over each item and display them
   it = snapshot->Iterator();
-  while (!it->Done())
-  {
+  while (!it->Done()) {
     Sample min;
     Sample max;
     Count count;
     it->Get(&min, &max, &count);
 
     // value is min, so display it
-    string range = GetSimpleAsciiBucketRange(min);
+    std::string range = GetSimpleAsciiBucketRange(min);
     output->append(range);
     for (size_t j = 0; range.size() + j < print_width + 1; ++j)
       output->push_back(' ');
diff --git a/base/metrics/sparse_histogram.h b/base/metrics/sparse_histogram.h
index 8c05613..241d975 100644
--- a/base/metrics/sparse_histogram.h
+++ b/base/metrics/sparse_histogram.h
@@ -28,7 +28,7 @@
 
 class HistogramSamples;
 
-class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
+class BASE_EXPORT SparseHistogram : public HistogramBase {
  public:
   // If there's one with same name, return the existing one. If not, create a
   // new one.
@@ -42,23 +42,24 @@
                                 Sample expected_maximum,
                                 size_t expected_bucket_count) const override;
   void Add(Sample value) override;
+  void AddCount(Sample value, int count) override;
   void AddSamples(const HistogramSamples& samples) override;
-  bool AddSamplesFromPickle(PickleIterator* iter) override;
+  bool AddSamplesFromPickle(base::PickleIterator* iter) override;
   scoped_ptr<HistogramSamples> SnapshotSamples() const override;
   void WriteHTMLGraph(std::string* output) const override;
   void WriteAscii(std::string* output) const override;
 
  protected:
   // HistogramBase implementation:
-  bool SerializeInfoImpl(Pickle* pickle) const override;
+  bool SerializeInfoImpl(base::Pickle* pickle) const override;
 
  private:
   // Clients should always use FactoryGet to create SparseHistogram.
   explicit SparseHistogram(const std::string& name);
 
-  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
-      PickleIterator* iter);
-  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
 
   void GetParameters(DictionaryValue* params) const override;
   void GetCountAndBucketData(Count* count,
diff --git a/base/metrics/sparse_histogram_unittest.cc b/base/metrics/sparse_histogram_unittest.cc
index c29dd5e..83cf5d3 100644
--- a/base/metrics/sparse_histogram_unittest.cc
+++ b/base/metrics/sparse_histogram_unittest.cc
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/metrics/sparse_histogram.h"
+
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram_base.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/metrics/sample_map.h"
-#include "base/metrics/sparse_histogram.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/pickle.h"
 #include "base/strings/stringprintf.h"
@@ -61,6 +62,25 @@
   EXPECT_EQ(1, snapshot2->GetCount(101));
 }
 
+TEST_F(SparseHistogramTest, BasicTestAddCount) {
+  scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+  scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(0, snapshot->TotalCount());
+  EXPECT_EQ(0, snapshot->sum());
+
+  histogram->AddCount(100, 15);
+  scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
+  EXPECT_EQ(15, snapshot1->TotalCount());
+  EXPECT_EQ(15, snapshot1->GetCount(100));
+
+  histogram->AddCount(100, 15);
+  histogram->AddCount(101, 25);
+  scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(55, snapshot2->TotalCount());
+  EXPECT_EQ(30, snapshot2->GetCount(100));
+  EXPECT_EQ(25, snapshot2->GetCount(101));
+}
+
 TEST_F(SparseHistogramTest, MacroBasicTest) {
   UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100);
   UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 200);
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index fb069a5..87ffa3d 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -10,13 +10,11 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
+#include "base/stl_util.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_ =
@@ -59,11 +57,20 @@
     if (histograms_ == NULL) {
       histogram_to_return = histogram;
     } else {
-      const string& name = histogram->histogram_name();
-      HistogramMap::iterator it = histograms_->find(name);
+      const std::string& name = histogram->histogram_name();
+      HistogramMap::iterator it = histograms_->find(HistogramNameRef(name));
       if (histograms_->end() == it) {
-        (*histograms_)[name] = histogram;
+        (*histograms_)[HistogramNameRef(name)] = histogram;
         ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
+        // If there are callbacks for this histogram, we set the kCallbackExists
+        // flag.
+        auto callback_iterator = callbacks_->find(name);
+        if (callback_iterator != callbacks_->end()) {
+          if (!callback_iterator->second.is_null())
+            histogram->SetFlags(HistogramBase::kCallbackExists);
+          else
+            histogram->ClearFlags(HistogramBase::kCallbackExists);
+        }
         histogram_to_return = histogram;
       } else if (histogram == it->second) {
         // The histogram was registered before.
@@ -96,22 +103,18 @@
     return ranges;
   }
 
-  list<const BucketRanges*>* checksum_matching_list;
+  std::list<const BucketRanges*>* checksum_matching_list;
   RangesMap::iterator ranges_it = ranges_->find(ranges->checksum());
   if (ranges_->end() == ranges_it) {
     // Add a new matching list to map.
-    checksum_matching_list = new list<const BucketRanges*>();
+    checksum_matching_list = new std::list<const BucketRanges*>();
     ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list);
     (*ranges_)[ranges->checksum()] = checksum_matching_list;
   } else {
     checksum_matching_list = ranges_it->second;
   }
 
-  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;
+  for (const BucketRanges* existing_ranges : *checksum_matching_list) {
     if (existing_ranges->Equals(ranges)) {
       if (existing_ranges == ranges) {
         return ranges;
@@ -135,10 +138,8 @@
 
   Histograms snapshot;
   GetSnapshot(query, &snapshot);
-  for (Histograms::iterator it = snapshot.begin();
-       it != snapshot.end();
-       ++it) {
-    (*it)->WriteHTMLGraph(output);
+  for (const HistogramBase* histogram : snapshot) {
+    histogram->WriteHTMLGraph(output);
     output->append("<br><hr><br>");
   }
 }
@@ -155,10 +156,8 @@
 
   Histograms snapshot;
   GetSnapshot(query, &snapshot);
-  for (Histograms::iterator it = snapshot.begin();
-       it != snapshot.end();
-       ++it) {
-    (*it)->WriteAscii(output);
+  for (const HistogramBase* histogram : snapshot) {
+    histogram->WriteAscii(output);
     output->append("\n");
   }
 }
@@ -179,14 +178,13 @@
   GetSnapshot(query, &snapshot);
   output += "\"histograms\":[";
   bool first_histogram = true;
-  for (Histograms::const_iterator it = snapshot.begin(); it != snapshot.end();
-       ++it) {
+  for (const HistogramBase* histogram : snapshot) {
     if (first_histogram)
       first_histogram = false;
     else
       output += ",";
     std::string json;
-    (*it)->WriteJSON(&json);
+    histogram->WriteJSON(&json);
     output += json;
   }
   output += "]}";
@@ -201,11 +199,9 @@
   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);
+  for (const auto& entry : *histograms_) {
+    DCHECK_EQ(entry.first.name_, entry.second->histogram_name());
+    output->push_back(entry.second);
   }
 }
 
@@ -218,15 +214,9 @@
   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);
+  for (const auto& entry : *ranges_) {
+    for (const auto& range_entry : *entry.second) {
+      output->push_back(range_entry);
     }
   }
 }
@@ -239,12 +229,64 @@
   if (histograms_ == NULL)
     return NULL;
 
-  HistogramMap::iterator it = histograms_->find(name);
+  HistogramMap::iterator it = histograms_->find(HistogramNameRef(name));
   if (histograms_->end() == it)
     return NULL;
   return it->second;
 }
 
+// static
+bool StatisticsRecorder::SetCallback(
+    const std::string& name,
+    const StatisticsRecorder::OnSampleCallback& cb) {
+  DCHECK(!cb.is_null());
+  if (lock_ == NULL)
+    return false;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return false;
+
+  if (ContainsKey(*callbacks_, name))
+    return false;
+  callbacks_->insert(std::make_pair(name, cb));
+
+  auto histogram_iterator = histograms_->find(HistogramNameRef(name));
+  if (histogram_iterator != histograms_->end())
+    histogram_iterator->second->SetFlags(HistogramBase::kCallbackExists);
+
+  return true;
+}
+
+// static
+void StatisticsRecorder::ClearCallback(const std::string& name) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return;
+
+  callbacks_->erase(name);
+
+  // We also clear the flag from the histogram (if it exists).
+  auto histogram_iterator = histograms_->find(HistogramNameRef(name));
+  if (histogram_iterator != histograms_->end())
+    histogram_iterator->second->ClearFlags(HistogramBase::kCallbackExists);
+}
+
+// static
+StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback(
+    const std::string& name) {
+  if (lock_ == NULL)
+    return OnSampleCallback();
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return OnSampleCallback();
+
+  auto callback_iterator = callbacks_->find(name);
+  return callback_iterator != callbacks_->end() ? callback_iterator->second
+                                                : OnSampleCallback();
+}
+
 // private static
 void StatisticsRecorder::GetSnapshot(const std::string& query,
                                      Histograms* snapshot) {
@@ -254,11 +296,9 @@
   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);
+  for (const auto& entry : *histograms_) {
+    if (entry.first.name_.find(query) != std::string::npos)
+      snapshot->push_back(entry.second);
   }
 }
 
@@ -278,6 +318,7 @@
   }
   base::AutoLock auto_lock(*lock_);
   histograms_ = new HistogramMap;
+  callbacks_ = new CallbackMap;
   ranges_ = new RangesMap;
 
   if (VLOG_IS_ON(1))
@@ -286,7 +327,7 @@
 
 // static
 void StatisticsRecorder::DumpHistogramsToVlog(void* instance) {
-  string output;
+  std::string output;
   StatisticsRecorder::WriteGraph(std::string(), &output);
   VLOG(1) << output;
 }
@@ -296,14 +337,17 @@
 
   // Clean up.
   scoped_ptr<HistogramMap> histograms_deleter;
+  scoped_ptr<CallbackMap> callbacks_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_);
+    callbacks_deleter.reset(callbacks_);
     ranges_deleter.reset(ranges_);
     histograms_ = NULL;
+    callbacks_ = NULL;
     ranges_ = NULL;
   }
   // We are going to leak the histograms and the ranges.
@@ -313,6 +357,8 @@
 // static
 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
 // static
+StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = NULL;
+// static
 StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
 // static
 base::Lock* StatisticsRecorder::lock_ = NULL;
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index b523057..0e5168f 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -17,13 +17,14 @@
 
 #include "base/base_export.h"
 #include "base/basictypes.h"
+#include "base/callback.h"
 #include "base/gtest_prod_util.h"
 #include "base/lazy_instance.h"
+#include "base/metrics/histogram_base.h"
 
 namespace base {
 
 class BucketRanges;
-class HistogramBase;
 class Lock;
 
 class BASE_EXPORT StatisticsRecorder {
@@ -75,9 +76,47 @@
   // histograms).
   static void GetSnapshot(const std::string& query, Histograms* snapshot);
 
+  typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;
+
+  // SetCallback sets the callback to notify when a new sample is recorded on
+  // the histogram referred to by |histogram_name|. The call to this method can
+  // be be done before or after the histogram is created. This method is thread
+  // safe. The return value is whether or not the callback was successfully set.
+  static bool SetCallback(const std::string& histogram_name,
+                          const OnSampleCallback& callback);
+
+  // ClearCallback clears any callback set on the histogram referred to by
+  // |histogram_name|. This method is thread safe.
+  static void ClearCallback(const std::string& histogram_name);
+
+  // FindCallback retrieves the callback for the histogram referred to by
+  // |histogram_name|, or a null callback if no callback exists for this
+  // histogram. This method is thread safe.
+  static OnSampleCallback FindCallback(const std::string& histogram_name);
+
  private:
+  // HistogramNameRef holds a weak const ref to the name field of the associated
+  // Histogram object, allowing re-use of the underlying string storage for the
+  // map keys. The wrapper is required as using "const std::string&" as the key
+  // results in compile errors.
+  struct HistogramNameRef {
+    explicit HistogramNameRef(const std::string& name) : name_(name) {};
+
+    // Operator < is necessary to use this type as a std::map key.
+    bool operator<(const HistogramNameRef& other) const {
+      return name_ < other.name_;
+    }
+
+    // Weak, owned by the associated Histogram object.
+    const std::string& name_;
+  };
+
   // We keep all registered histograms in a map, from name to histogram.
-  typedef std::map<std::string, HistogramBase*> HistogramMap;
+  typedef std::map<HistogramNameRef, HistogramBase*> HistogramMap;
+
+  // We keep a map of callbacks to histograms, so that as histograms are
+  // created, we can set the callback properly.
+  typedef std::map<std::string, OnSampleCallback> CallbackMap;
 
   // We keep all |bucket_ranges_| in a map, from checksum to a list of
   // |bucket_ranges_|.  Checksum is calculated from the |ranges_| in
@@ -103,6 +142,7 @@
   static void DumpHistogramsToVlog(void* instance);
 
   static HistogramMap* histograms_;
+  static CallbackMap* callbacks_;
   static RangesMap* ranges_;
 
   // Lock protects access to above maps.
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
index e653bf3..29caf49 100644
--- a/base/metrics/statistics_recorder_unittest.cc
+++ b/base/metrics/statistics_recorder_unittest.cc
@@ -4,9 +4,11 @@
 
 #include <vector>
 
+#include "base/bind.h"
 #include "base/json/json_reader.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -261,8 +263,7 @@
   std::string json(StatisticsRecorder::ToJSON(std::string()));
 
   // Check for valid JSON.
-  scoped_ptr<Value> root;
-  root.reset(JSONReader::Read(json));
+  scoped_ptr<Value> root = JSONReader::Read(json);
   ASSERT_TRUE(root.get());
 
   DictionaryValue* root_dict = NULL;
@@ -287,7 +288,7 @@
   std::string query("TestHistogram2");
   json = StatisticsRecorder::ToJSON(query);
 
-  root.reset(JSONReader::Read(json));
+  root = JSONReader::Read(json);
   ASSERT_TRUE(root.get());
   ASSERT_TRUE(root->GetAsDictionary(&root_dict));
 
@@ -312,4 +313,178 @@
   EXPECT_TRUE(json.empty());
 }
 
+namespace {
+
+// CallbackCheckWrapper is simply a convenient way to check and store that
+// a callback was actually run.
+struct CallbackCheckWrapper {
+  CallbackCheckWrapper() : called(false), last_histogram_value(0) {}
+
+  void OnHistogramChanged(base::HistogramBase::Sample histogram_value) {
+    called = true;
+    last_histogram_value = histogram_value;
+  }
+
+  bool called;
+  base::HistogramBase::Sample last_histogram_value;
+};
+
+}  // namespace
+
+// Check that you can't overwrite the callback with another.
+TEST_F(StatisticsRecorderTest, SetCallbackFailsWithoutHistogramTest) {
+  CallbackCheckWrapper callback_wrapper;
+
+  bool result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_TRUE(result);
+
+  result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_FALSE(result);
+}
+
+// Check that you can't overwrite the callback with another.
+TEST_F(StatisticsRecorderTest, SetCallbackFailsWithHistogramTest) {
+  HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+                                                   HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+
+  CallbackCheckWrapper callback_wrapper;
+
+  bool result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_TRUE(result);
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+            base::HistogramBase::kCallbackExists);
+
+  result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_FALSE(result);
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+            base::HistogramBase::kCallbackExists);
+
+  histogram->Add(1);
+
+  EXPECT_TRUE(callback_wrapper.called);
+}
+
+// Check that you can't overwrite the callback with another.
+TEST_F(StatisticsRecorderTest, ClearCallbackSuceedsWithHistogramTest) {
+  HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+                                                   HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+
+  CallbackCheckWrapper callback_wrapper;
+
+  bool result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_TRUE(result);
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+            base::HistogramBase::kCallbackExists);
+
+  base::StatisticsRecorder::ClearCallback("TestHistogram");
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, 0);
+
+  histogram->Add(1);
+
+  EXPECT_FALSE(callback_wrapper.called);
+}
+
+// Check that callback is used.
+TEST_F(StatisticsRecorderTest, CallbackUsedTest) {
+  {
+    HistogramBase* histogram = Histogram::FactoryGet(
+        "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+    EXPECT_TRUE(histogram);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                    base::Unretained(&callback_wrapper)));
+
+    histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+
+  {
+    HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+        "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestLinearHistogram",
+        base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                   base::Unretained(&callback_wrapper)));
+
+    linear_histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+
+  {
+    std::vector<int> custom_ranges;
+    custom_ranges.push_back(1);
+    custom_ranges.push_back(5);
+    HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
+        "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestCustomHistogram",
+        base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                   base::Unretained(&callback_wrapper)));
+
+    custom_histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+
+  {
+    HistogramBase* custom_histogram = SparseHistogram::FactoryGet(
+        "TestSparseHistogram", HistogramBase::kNoFlags);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestSparseHistogram",
+        base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                   base::Unretained(&callback_wrapper)));
+
+    custom_histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+}
+
+// Check that setting a callback before the histogram exists works.
+TEST_F(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
+  CallbackCheckWrapper callback_wrapper;
+
+  base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+
+  HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+                                                   HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+  histogram->Add(1);
+
+  EXPECT_TRUE(callback_wrapper.called);
+  EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+}
+
 }  // namespace base
diff --git a/base/move.h b/base/move.h
index 87dc52d..fe0517e 100644
--- a/base/move.h
+++ b/base/move.h
@@ -5,9 +5,11 @@
 #ifndef BASE_MOVE_H_
 #define BASE_MOVE_H_
 
+#include <utility>
+
 #include "base/compiler_specific.h"
 
-// Macro with the boilerplate that makes a type move-only in C++03.
+// Macro with the boilerplate that makes a type move-only in C++11.
 //
 // USAGE
 //
@@ -22,121 +24,21 @@
 //   * 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:
+// 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 a hypothetical scoped_ptr class:
 //
 //  template <typename T>
 //  class scoped_ptr {
-//     MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+//    MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type);
 //   public:
-//    scoped_ptr(RValue& other) : ptr_(other.release()) { }
-//    scoped_ptr& operator=(RValue& other) {
-//      swap(other);
+//    scoped_ptr(scoped_ptr&& other) : ptr_(other.release()) { }
+//    scoped_ptr& operator=(scoped_ptr&& other) {
+//      reset(other.release());
 //      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
 //
@@ -146,89 +48,24 @@
 // 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; \
+#define MOVE_ONLY_TYPE_FOR_CPP_03(type) \
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type)
+
+#define MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type)   \
+ private:                                                       \
+  type(const type&) = delete;                                   \
+  void operator=(const type&) = delete;                         \
+                                                                \
+ public:                                                        \
+  type&& Pass() WARN_UNUSED_RESULT { return std::move(*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); } \
+  type&& Pass() WARN_UNUSED_RESULT { return std::move(*this); } \
  private:
 
 #endif  // BASE_MOVE_H_
diff --git a/base/move_unittest.cc b/base/move_unittest.cc
deleted file mode 100644
index 1f4ce84..0000000
--- a/base/move_unittest.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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_ios.mm b/base/native_library_ios.mm
index 030c171..60a11f2 100644
--- a/base/native_library_ios.mm
+++ b/base/native_library_ios.mm
@@ -16,6 +16,8 @@
 NativeLibrary LoadNativeLibrary(const base::FilePath& library_path,
                                 NativeLibraryLoadError* error) {
   NOTIMPLEMENTED();
+  if (error)
+    error->message = "Not implemented.";
   return nullptr;
 }
 
diff --git a/base/native_library_mac.mm b/base/native_library_mac.mm
index 8122c28..1684885 100644
--- a/base/native_library_mac.mm
+++ b/base/native_library_mac.mm
@@ -52,7 +52,8 @@
   if (library_path.Extension() == "dylib" || !DirectoryExists(library_path)) {
     void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY);
     if (!dylib) {
-      error->message = dlerror();
+      if (error)
+        error->message = dlerror();
       return NULL;
     }
     NativeLibrary native_lib = new NativeLibraryStruct();
diff --git a/base/native_library_unittest.cc b/base/native_library_unittest.cc
new file mode 100644
index 0000000..b3cff1d
--- /dev/null
+++ b/base/native_library_unittest.cc
@@ -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.
+
+#include "base/files/file_path.h"
+#include "base/native_library.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+const FilePath::CharType kDummyLibraryPath[] =
+    FILE_PATH_LITERAL("dummy_library");
+
+TEST(NativeLibraryTest, LoadFailure) {
+  NativeLibraryLoadError error;
+  NativeLibrary library =
+      LoadNativeLibrary(FilePath(kDummyLibraryPath), &error);
+  EXPECT_TRUE(library == nullptr);
+  EXPECT_FALSE(error.ToString().empty());
+}
+
+// |error| is optional and can be null.
+TEST(NativeLibraryTest, LoadFailureWithNullError) {
+  NativeLibrary library =
+      LoadNativeLibrary(FilePath(kDummyLibraryPath), nullptr);
+  EXPECT_TRUE(library == nullptr);
+}
+
+}  // namespace base
diff --git a/base/nix/xdg_util.cc b/base/nix/xdg_util.cc
index ef04561..f76c0cb 100644
--- a/base/nix/xdg_util.cc
+++ b/base/nix/xdg_util.cc
@@ -15,8 +15,8 @@
 
 namespace {
 
-// The KDE session version environment variable used in KDE 4.
-const char kKDE4SessionEnvVar[] = "KDE_SESSION_VERSION";
+// The KDE session version environment variable introduced in KDE 4.
+const char kKDESessionEnvVar[] = "KDE_SESSION_VERSION";
 
 }  // namespace
 
@@ -69,6 +69,12 @@
     } else if (xdg_current_desktop == "GNOME") {
       return DESKTOP_ENVIRONMENT_GNOME;
     } else if (xdg_current_desktop == "KDE") {
+      std::string kde_session;
+      if (env->GetVar(kKDESessionEnvVar, &kde_session)) {
+        if (kde_session == "5") {
+          return DESKTOP_ENVIRONMENT_KDE5;
+        }
+      }
       return DESKTOP_ENVIRONMENT_KDE4;
     }
   }
@@ -82,7 +88,7 @@
       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))
+      if (env->HasVar(kKDESessionEnvVar))
         return DESKTOP_ENVIRONMENT_KDE4;
       return DESKTOP_ENVIRONMENT_KDE3;
     } else if (desktop_session.find("xfce") != std::string::npos ||
@@ -96,7 +102,7 @@
   if (env->HasVar("GNOME_DESKTOP_SESSION_ID")) {
     return DESKTOP_ENVIRONMENT_GNOME;
   } else if (env->HasVar("KDE_FULL_SESSION")) {
-    if (env->HasVar(kKDE4SessionEnvVar))
+    if (env->HasVar(kKDESessionEnvVar))
       return DESKTOP_ENVIRONMENT_KDE4;
     return DESKTOP_ENVIRONMENT_KDE3;
   }
@@ -114,6 +120,8 @@
       return "KDE3";
     case DESKTOP_ENVIRONMENT_KDE4:
       return "KDE4";
+    case DESKTOP_ENVIRONMENT_KDE5:
+      return "KDE5";
     case DESKTOP_ENVIRONMENT_UNITY:
       return "UNITY";
     case DESKTOP_ENVIRONMENT_XFCE:
diff --git a/base/nix/xdg_util.h b/base/nix/xdg_util.h
index a8b7784..8812c61 100644
--- a/base/nix/xdg_util.h
+++ b/base/nix/xdg_util.h
@@ -48,10 +48,11 @@
 enum DesktopEnvironment {
   DESKTOP_ENVIRONMENT_OTHER,
   DESKTOP_ENVIRONMENT_GNOME,
-  // KDE3 and KDE4 are sufficiently different that we count
-  // them as two different desktop environments here.
+  // KDE3, KDE4 and KDE5 are sufficiently different that we count
+  // them as different desktop environments here.
   DESKTOP_ENVIRONMENT_KDE3,
   DESKTOP_ENVIRONMENT_KDE4,
+  DESKTOP_ENVIRONMENT_KDE5,
   DESKTOP_ENVIRONMENT_UNITY,
   DESKTOP_ENVIRONMENT_XFCE,
 };
diff --git a/base/nix/xdg_util_unittest.cc b/base/nix/xdg_util_unittest.cc
index 136eb5d..a054355 100644
--- a/base/nix/xdg_util_unittest.cc
+++ b/base/nix/xdg_util_unittest.cc
@@ -35,8 +35,10 @@
 const char* const kXdgDesktopGNOME = "GNOME";
 const char* const kXdgDesktopKDE = "KDE";
 const char* const kXdgDesktopUnity = "Unity";
+const char* const kKDESessionKDE5 = "5";
 
 const char kDesktopSession[] = "DESKTOP_SESSION";
+const char kKDESession[] = "KDE_SESSION_VERSION";
 const char kXdgDesktop[] = "XDG_CURRENT_DESKTOP";
 
 }  // namespace
@@ -107,6 +109,17 @@
   EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
 }
 
+TEST(XDGUtilTest, GetXdgDesktopKDE5) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopKDE), Return(true)));
+  EXPECT_CALL(getter, GetVar(StrEq(kKDESession), _))
+        .WillOnce(DoAll(SetArgumentPointee<1>(kKDESessionKDE5), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE5, GetDesktopEnvironment(&getter));
+}
+
 TEST(XDGUtilTest, GetXdgDesktopKDE4) {
   MockEnvironment getter;
   EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h
index d9b77f7..5e5ed77 100644
--- a/base/numerics/safe_conversions.h
+++ b/base/numerics/safe_conversions.h
@@ -6,6 +6,7 @@
 #define BASE_NUMERICS_SAFE_CONVERSIONS_H_
 
 #include <limits>
+#include <type_traits>
 
 #include "base/logging.h"
 #include "base/numerics/safe_conversions_impl.h"
@@ -20,6 +21,24 @@
          internal::RANGE_VALID;
 }
 
+// Convenience function for determining if a numeric value is negative without
+// throwing compiler warnings on: unsigned(value) < 0.
+template <typename T>
+typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
+IsValueNegative(T value) {
+  static_assert(std::numeric_limits<T>::is_specialized,
+                "Argument must be numeric.");
+  return value < 0;
+}
+
+template <typename T>
+typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
+    IsValueNegative(T) {
+  static_assert(std::numeric_limits<T>::is_specialized,
+                "Argument must be numeric.");
+  return false;
+}
+
 // checked_cast<> is analogous to static_cast<> for numeric types,
 // except that it CHECKs that the specified numeric conversion will not
 // overflow or underflow. NaN source will always trigger a CHECK.
@@ -58,6 +77,68 @@
   return static_cast<Dst>(value);
 }
 
+// strict_cast<> is analogous to static_cast<> for numeric types, except that
+// it will cause a compile failure if the destination type is not large enough
+// to contain any value in the source type. It performs no runtime checking.
+template <typename Dst, typename Src>
+inline Dst strict_cast(Src value) {
+  static_assert(std::numeric_limits<Src>::is_specialized,
+                "Argument must be numeric.");
+  static_assert(std::numeric_limits<Dst>::is_specialized,
+                "Result must be numeric.");
+  static_assert((internal::StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
+                 internal::NUMERIC_RANGE_CONTAINED),
+                "The numeric conversion is out of range for this type. You "
+                "should probably use one of the following conversion "
+                "mechanisms on the value you want to pass:\n"
+                "- base::checked_cast\n"
+                "- base::saturated_cast\n"
+                "- base::CheckedNumeric");
+
+  return static_cast<Dst>(value);
+}
+
+// StrictNumeric implements compile time range checking between numeric types by
+// wrapping assignment operations in a strict_cast. This class is intended to be
+// used for function arguments and return types, to ensure the destination type
+// can always contain the source type. This is essentially the same as enforcing
+// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied
+// incrementally at API boundaries, making it easier to convert code so that it
+// compiles cleanly with truncation warnings enabled.
+// This template should introduce no runtime overhead, but it also provides no
+// runtime checking of any of the associated mathematical operations. Use
+// CheckedNumeric for runtime range checks of tha actual value being assigned.
+template <typename T>
+class StrictNumeric {
+ public:
+  typedef T type;
+
+  StrictNumeric() : value_(0) {}
+
+  // Copy constructor.
+  template <typename Src>
+  StrictNumeric(const StrictNumeric<Src>& rhs)
+      : value_(strict_cast<T>(rhs.value_)) {}
+
+  // This is not an explicit constructor because we implicitly upgrade regular
+  // numerics to StrictNumerics to make them easier to use.
+  template <typename Src>
+  StrictNumeric(Src value)
+      : value_(strict_cast<T>(value)) {}
+
+  // The numeric cast operator basically handles all the magic.
+  template <typename Dst>
+  operator Dst() const {
+    return strict_cast<Dst>(value_);
+  }
+
+ private:
+  T value_;
+};
+
+// Explicitly make a shorter size_t typedef for convenience.
+typedef StrictNumeric<size_t> SizeT;
+
 }  // namespace base
 
 #endif  // BASE_NUMERICS_SAFE_CONVERSIONS_H_
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h
index 504ce7e..f4bc916 100644
--- a/base/numerics/safe_conversions_impl.h
+++ b/base/numerics/safe_conversions_impl.h
@@ -108,6 +108,55 @@
                             (is_in_lower_bound ? 0 : RANGE_UNDERFLOW));
 }
 
+// The following helper template addresses a corner case in range checks for
+// conversion from a floating-point type to an integral type of smaller range
+// but larger precision (e.g. float -> unsigned). The problem is as follows:
+//   1. Integral maximum is always one less than a power of two, so it must be
+//      truncated to fit the mantissa of the floating point. The direction of
+//      rounding is implementation defined, but by default it's always IEEE
+//      floats, which round to nearest and thus result in a value of larger
+//      magnitude than the integral value.
+//      Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
+//                                   // is 4294967295u.
+//   2. If the floating point value is equal to the promoted integral maximum
+//      value, a range check will erroneously pass.
+//      Example: (4294967296f <= 4294967295u) // This is true due to a precision
+//                                            // loss in rounding up to float.
+//   3. When the floating point value is then converted to an integral, the
+//      resulting value is out of range for the target integral type and
+//      thus is implementation defined.
+//      Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
+// To fix this bug we manually truncate the maximum value when the destination
+// type is an integral of larger precision than the source floating-point type,
+// such that the resulting maximum is represented exactly as a floating point.
+template <typename Dst, typename Src>
+struct NarrowingRange {
+  typedef typename std::numeric_limits<Src> SrcLimits;
+  typedef typename std::numeric_limits<Dst> DstLimits;
+
+  static Dst max() {
+    // The following logic avoids warnings where the max function is
+    // instantiated with invalid values for a bit shift (even though
+    // such a function can never be called).
+    static const int shift =
+        (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
+         SrcLimits::digits < DstLimits::digits && SrcLimits::is_iec559 &&
+         DstLimits::is_integer)
+            ? (DstLimits::digits - SrcLimits::digits)
+            : 0;
+
+    // We use UINTMAX_C below to avoid compiler warnings about shifting floating
+    // points. Since it's a compile time calculation, it shouldn't have any
+    // performance impact.
+    return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1);
+  }
+
+  static Dst min() {
+    return std::numeric_limits<Dst>::is_iec559 ? -DstLimits::max()
+                                               : DstLimits::min();
+  }
+};
+
 template <
     typename Dst,
     typename Src,
@@ -147,11 +196,8 @@
                                       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());
+    return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()),
+                              (value >= NarrowingRange<Dst, Src>::min()));
   }
 };
 
@@ -163,7 +209,7 @@
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
   static RangeConstraint Check(Src value) {
-    return GetRangeConstraint(value <= std::numeric_limits<Dst>::max(), true);
+    return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::max(), true);
   }
 };
 
@@ -178,7 +224,7 @@
     return sizeof(Dst) > sizeof(Src)
                ? RANGE_VALID
                : GetRangeConstraint(
-                     value <= static_cast<Src>(std::numeric_limits<Dst>::max()),
+                     value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
                      true);
   }
 };
@@ -195,7 +241,7 @@
     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>(NarrowingRange<Dst, Src>::max()),
                      value >= static_cast<Src>(0));
   }
 };
diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h
index 1309446..cbf00f0 100644
--- a/base/numerics/safe_math.h
+++ b/base/numerics/safe_math.h
@@ -66,6 +66,13 @@
                   "Argument must be numeric.");
   }
 
+  // This is not an explicit constructor because we want a seamless conversion
+  // from StrictNumeric types.
+  template <typename Src>
+  CheckedNumeric(StrictNumeric<Src> value)
+      : state_(static_cast<Src>(value)) {
+  }
+
   // IsValid() is the public API to test if a CheckedNumeric is currently valid.
   bool IsValid() const { return validity() == RANGE_VALID; }
 
@@ -138,6 +145,14 @@
     return CheckedNumeric<T>(value, validity);
   }
 
+  // This function is available only for integral types. It returns an unsigned
+  // integer of the same width as the source type, containing the absolute value
+  // of the source, and properly handling signed min.
+  CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const {
+    return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>(
+        CheckedUnsignedAbs(state_.value()), state_.validity());
+  }
+
   CheckedNumeric& operator++() {
     *this += 1;
     return *this;
@@ -166,21 +181,31 @@
   template <typename Src>
   static CheckedNumeric<T> cast(
       Src u,
-      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
-          0) {
+      typename std::enable_if<std::numeric_limits<Src>::is_specialized,
+                              int>::type = 0) {
     return u;
   }
 
   template <typename Src>
   static CheckedNumeric<T> cast(
       const CheckedNumeric<Src>& u,
-      typename enable_if<!is_same<Src, T>::value, int>::type = 0) {
+      typename std::enable_if<!is_same<Src, T>::value, int>::type = 0) {
     return u;
   }
 
   static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
 
  private:
+  template <typename NumericType>
+  struct UnderlyingType {
+    using type = NumericType;
+  };
+
+  template <typename NumericType>
+  struct UnderlyingType<CheckedNumeric<NumericType>> {
+    using type = NumericType;
+  };
+
   CheckedNumericState<T> state_;
 };
 
@@ -217,7 +242,8 @@
   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); \
+    *this = CheckedNumeric<T>::cast(*this)                                    \
+        OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs);     \
     return *this;                                                             \
   }                                                                           \
   /* Binary arithmetic operator for CheckedNumeric of different type. */      \
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
index c845189..d6977f4 100644
--- a/base/numerics/safe_math_impl.h
+++ b/base/numerics/safe_math_impl.h
@@ -10,6 +10,7 @@
 #include <cmath>
 #include <cstdlib>
 #include <limits>
+#include <type_traits>
 
 #include "base/numerics/safe_conversions.h"
 #include "base/template_util.h"
@@ -63,21 +64,21 @@
 
 template <typename Integer>
 struct UnsignedIntegerForSize {
-  typedef typename enable_if<
+  typedef typename std::enable_if<
       std::numeric_limits<Integer>::is_integer,
       typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
 };
 
 template <typename Integer>
 struct SignedIntegerForSize {
-  typedef typename enable_if<
+  typedef typename std::enable_if<
       std::numeric_limits<Integer>::is_integer,
       typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
 };
 
 template <typename Integer>
 struct TwiceWiderInteger {
-  typedef typename enable_if<
+  typedef typename std::enable_if<
       std::numeric_limits<Integer>::is_integer,
       typename IntegerForSizeAndSign<
           sizeof(Integer) * 2,
@@ -86,8 +87,28 @@
 
 template <typename Integer>
 struct PositionOfSignBit {
-  static const typename enable_if<std::numeric_limits<Integer>::is_integer,
-                                  size_t>::type value = 8 * sizeof(Integer) - 1;
+  static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
+                                       size_t>::type value =
+      8 * sizeof(Integer) - 1;
+};
+
+// This is used for UnsignedAbs, where we need to support floating-point
+// template instantiations even though we don't actually support the operations.
+// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs,
+// so the float versions will not compile.
+template <typename Numeric,
+          bool IsInteger = std::numeric_limits<Numeric>::is_integer,
+          bool IsFloat = std::numeric_limits<Numeric>::is_iec559>
+struct UnsignedOrFloatForSize;
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, true, false> {
+  typedef typename UnsignedIntegerForSize<Numeric>::type type;
+};
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, false, true> {
+  typedef Numeric type;
 };
 
 // Helper templates for integer manipulations.
@@ -110,7 +131,7 @@
 // way to coalesce things into the CheckedNumericState specializations below.
 
 template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
 CheckedAdd(T x, T y, RangeConstraint* validity) {
   // Since the value of x+y is undefined if we have a signed type, we compute
   // it using the unsigned type of the same size.
@@ -133,7 +154,7 @@
 }
 
 template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
 CheckedSub(T x, T y, RangeConstraint* validity) {
   // Since the value of x+y is undefined if we have a signed type, we compute
   // it using the unsigned type of the same size.
@@ -160,9 +181,9 @@
 // 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
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            sizeof(T) * 2 <= sizeof(uintmax_t),
+                        T>::type
 CheckedMul(T x, T y, RangeConstraint* validity) {
   typedef typename TwiceWiderInteger<T>::type IntermediateType;
   IntermediateType tmp =
@@ -172,12 +193,13 @@
 }
 
 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
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            std::numeric_limits<T>::is_signed &&
+                            (sizeof(T) * 2 > sizeof(uintmax_t)),
+                        T>::type
 CheckedMul(T x, T y, RangeConstraint* validity) {
-  // if either side is zero then the result will be zero.
-  if (!(x || y)) {
+  // If either side is zero then the result will be zero.
+  if (!x || !y) {
     return RANGE_VALID;
 
   } else if (x > 0) {
@@ -201,10 +223,10 @@
 }
 
 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
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            !std::numeric_limits<T>::is_signed &&
+                            (sizeof(T) * 2 > sizeof(uintmax_t)),
+                        T>::type
 CheckedMul(T x, T y, RangeConstraint* validity) {
   *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
                   ? RANGE_VALID
@@ -214,11 +236,11 @@
 
 // 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) {
+T CheckedDiv(T x,
+             T y,
+             RangeConstraint* validity,
+             typename std::enable_if<std::numeric_limits<T>::is_integer,
+                                     int>::type = 0) {
   if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
       y == static_cast<T>(-1)) {
     *validity = RANGE_OVERFLOW;
@@ -230,27 +252,27 @@
 }
 
 template <typename T>
-typename enable_if<
-    std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
-    T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            std::numeric_limits<T>::is_signed,
+                        T>::type
 CheckedMod(T x, T y, RangeConstraint* validity) {
   *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
   return x % y;
 }
 
 template <typename T>
-typename enable_if<
-    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
-    T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            !std::numeric_limits<T>::is_signed,
+                        T>::type
 CheckedMod(T x, T y, RangeConstraint* validity) {
   *validity = RANGE_VALID;
   return x % y;
 }
 
 template <typename T>
-typename enable_if<
-    std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
-    T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            std::numeric_limits<T>::is_signed,
+                        T>::type
 CheckedNeg(T value, RangeConstraint* validity) {
   *validity =
       value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
@@ -259,9 +281,9 @@
 }
 
 template <typename T>
-typename enable_if<
-    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
-    T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            !std::numeric_limits<T>::is_signed,
+                        T>::type
 CheckedNeg(T value, RangeConstraint* validity) {
   // The only legal unsigned negation is zero.
   *validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
@@ -270,9 +292,9 @@
 }
 
 template <typename T>
-typename enable_if<
-    std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
-    T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            std::numeric_limits<T>::is_signed,
+                        T>::type
 CheckedAbs(T value, RangeConstraint* validity) {
   *validity =
       value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
@@ -280,23 +302,43 @@
 }
 
 template <typename T>
-typename enable_if<
-    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
-    T>::type
+typename std::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.
+  // T is unsigned, so |value| must already be positive.
   *validity = RANGE_VALID;
   return value;
 }
 
+template <typename T>
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            std::numeric_limits<T>::is_signed,
+                        typename UnsignedIntegerForSize<T>::type>::type
+CheckedUnsignedAbs(T value) {
+  typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
+  return value == std::numeric_limits<T>::min()
+             ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
+             : static_cast<UnsignedT>(std::abs(value));
+}
+
+template <typename T>
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            !std::numeric_limits<T>::is_signed,
+                        T>::type
+CheckedUnsignedAbs(T value) {
+  // T is unsigned, so |value| must already be positive.
+  return 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;                                                    \
+#define BASE_FLOAT_ARITHMETIC_STUBS(NAME)                             \
+  template <typename T>                                               \
+  typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
+      Checked##NAME(T, T, RangeConstraint*) {                         \
+    NOTREACHED();                                                     \
+    return 0;                                                         \
   }
 
 BASE_FLOAT_ARITHMETIC_STUBS(Add)
@@ -308,14 +350,14 @@
 #undef BASE_FLOAT_ARITHMETIC_STUBS
 
 template <typename T>
-typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
+typename std::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(
+typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
     T value,
     RangeConstraint*) {
   return std::abs(value);
@@ -375,8 +417,8 @@
   template <typename Src>
   explicit CheckedNumericState(
       Src value,
-      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
-          0)
+      typename std::enable_if<std::numeric_limits<Src>::is_specialized,
+                              int>::type = 0)
       : value_(static_cast<T>(value)),
         validity_(DstRangeRelationToSrcRange<T>(value)) {}
 
@@ -400,7 +442,8 @@
   CheckedNumericState(
       Src value,
       RangeConstraint validity,
-      typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) {
+      typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type =
+          0) {
     switch (DstRangeRelationToSrcRange<T>(value)) {
       case RANGE_VALID:
         value_ = static_cast<T>(value);
@@ -426,8 +469,8 @@
   template <typename Src>
   explicit CheckedNumericState(
       Src value,
-      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
-          0)
+      typename std::enable_if<std::numeric_limits<Src>::is_specialized,
+                              int>::type = 0)
       : value_(static_cast<T>(value)) {}
 
   // Copy constructor.
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc
index bdececb..aaf2779 100644
--- a/base/numerics/safe_numerics_unittest.cc
+++ b/base/numerics/safe_numerics_unittest.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <limits>
+#include <type_traits>
 
 #include "base/compiler_specific.h"
 #include "base/numerics/safe_conversions.h"
@@ -18,13 +19,18 @@
 using std::numeric_limits;
 using base::CheckedNumeric;
 using base::checked_cast;
+using base::IsValueInRangeForNumericType;
+using base::IsValueNegative;
+using base::SizeT;
+using base::StrictNumeric;
 using base::saturated_cast;
+using base::strict_cast;
 using base::internal::MaxExponent;
 using base::internal::RANGE_VALID;
 using base::internal::RANGE_INVALID;
 using base::internal::RANGE_OVERFLOW;
 using base::internal::RANGE_UNDERFLOW;
-using base::enable_if;
+using base::internal::SignedIntegerForSize;
 
 // These tests deliberately cause arithmetic overflows. If the compiler is
 // aggressive enough, it can const fold these overflows. Disable warnings about
@@ -33,6 +39,26 @@
 #pragma warning(disable:4756)
 #endif
 
+// This is a helper function for finding the maximum value in Src that can be
+// wholy represented as the destination floating-point type.
+template <typename Dst, typename Src>
+Dst GetMaxConvertibleToFloat() {
+  typedef numeric_limits<Dst> DstLimits;
+  typedef numeric_limits<Src> SrcLimits;
+  static_assert(SrcLimits::is_specialized, "Source must be numeric.");
+  static_assert(DstLimits::is_specialized, "Destination must be numeric.");
+  CHECK(DstLimits::is_iec559);
+
+  if (SrcLimits::digits <= DstLimits::digits &&
+      MaxExponent<Src>::value <= MaxExponent<Dst>::value)
+    return SrcLimits::max();
+  Src max = SrcLimits::max() / 2 + (SrcLimits::is_integer ? 1 : 0);
+  while (max != static_cast<Src>(static_cast<Dst>(max))) {
+    max /= 2;
+  }
+  return static_cast<Dst>(max);
+}
+
 // Helper macros to wrap displaying the conversion types and line numbers.
 #define TEST_EXPECTED_VALIDITY(expected, actual)                           \
   EXPECT_EQ(expected, CheckedNumeric<Dst>(actual).validity())              \
@@ -50,9 +76,9 @@
 static void TestSpecializedArithmetic(
     const char* dst,
     int line,
-    typename enable_if<
-        numeric_limits<Dst>::is_integer&& numeric_limits<Dst>::is_signed,
-        int>::type = 0) {
+    typename std::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()));
@@ -106,9 +132,9 @@
 static void TestSpecializedArithmetic(
     const char* dst,
     int line,
-    typename enable_if<
-        numeric_limits<Dst>::is_integer && !numeric_limits<Dst>::is_signed,
-        int>::type = 0) {
+    typename std::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,
@@ -119,6 +145,13 @@
                          CheckedNumeric<Dst>(DstLimits::min()) - 1);
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) * 2);
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2);
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()).UnsignedAbs());
+  TEST_EXPECTED_VALIDITY(
+      RANGE_VALID,
+      CheckedNumeric<typename SignedIntegerForSize<Dst>::type>(
+          std::numeric_limits<typename SignedIntegerForSize<Dst>::type>::min())
+          .UnsignedAbs());
 
   // Modulus is legal only for integers.
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1);
@@ -139,7 +172,7 @@
 void TestSpecializedArithmetic(
     const char* dst,
     int line,
-    typename enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
+    typename std::enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
   typedef numeric_limits<Dst> DstLimits;
   TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min()));
 
@@ -239,6 +272,9 @@
   TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>() * 1));
   TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>(1) * 1));
   TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) * 2));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * 0));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) * 0));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * -1));
   TEST_EXPECTED_VALIDITY(
       RANGE_OVERFLOW, CheckedNumeric<Dst>(DstLimits::max()) * DstLimits::max());
 
@@ -364,6 +400,18 @@
       TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
       TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+      if (DstLimits::is_integer) {
+        if (SrcLimits::digits < DstLimits::digits) {
+          TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
+                              static_cast<Src>(DstLimits::max()));
+        } else {
+          TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
+        }
+        TEST_EXPECTED_RANGE(
+            RANGE_VALID,
+            static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
+        TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min()));
+      }
     } else if (SrcLimits::is_signed) {
       TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1));
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
@@ -422,6 +470,18 @@
       TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
       TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+      if (DstLimits::is_integer) {
+        if (SrcLimits::digits < DstLimits::digits) {
+          TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
+                              static_cast<Src>(DstLimits::max()));
+        } else {
+          TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
+        }
+        TEST_EXPECTED_RANGE(
+            RANGE_VALID,
+            static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
+        TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min()));
+      }
     } else {
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
     }
@@ -556,9 +616,39 @@
   double double_small = 1.0;
   double double_large = numeric_limits<double>::max();
   double double_infinity = numeric_limits<float>::infinity();
+  double double_large_int = numeric_limits<int>::max();
+  double double_small_int = numeric_limits<int>::min();
 
-  // Just test that the cast compiles, since the other tests cover logic.
+  // Just test that the casts compile, since the other tests cover logic.
   EXPECT_EQ(0, checked_cast<int>(static_cast<size_t>(0)));
+  EXPECT_EQ(0, strict_cast<int>(static_cast<char>(0)));
+  EXPECT_EQ(0, strict_cast<int>(static_cast<unsigned char>(0)));
+  EXPECT_EQ(0U, strict_cast<unsigned>(static_cast<unsigned char>(0)));
+  EXPECT_EQ(1ULL, static_cast<uint64_t>(StrictNumeric<size_t>(1U)));
+  EXPECT_EQ(1ULL, static_cast<uint64_t>(SizeT(1U)));
+  EXPECT_EQ(1U, static_cast<size_t>(StrictNumeric<unsigned>(1U)));
+
+  EXPECT_TRUE(CheckedNumeric<uint64_t>(StrictNumeric<unsigned>(1U)).IsValid());
+  EXPECT_TRUE(CheckedNumeric<int>(StrictNumeric<unsigned>(1U)).IsValid());
+  EXPECT_FALSE(CheckedNumeric<unsigned>(StrictNumeric<int>(-1)).IsValid());
+
+  EXPECT_TRUE(IsValueNegative(-1));
+  EXPECT_TRUE(IsValueNegative(numeric_limits<int>::min()));
+  EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::min()));
+  EXPECT_TRUE(IsValueNegative(-numeric_limits<double>::max()));
+  EXPECT_FALSE(IsValueNegative(0));
+  EXPECT_FALSE(IsValueNegative(1));
+  EXPECT_FALSE(IsValueNegative(0u));
+  EXPECT_FALSE(IsValueNegative(1u));
+  EXPECT_FALSE(IsValueNegative(numeric_limits<int>::max()));
+  EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::max()));
+  EXPECT_FALSE(IsValueNegative(numeric_limits<double>::max()));
+
+  // These casts and coercions will fail to compile:
+  // EXPECT_EQ(0, strict_cast<int>(static_cast<size_t>(0)));
+  // EXPECT_EQ(0, strict_cast<size_t>(static_cast<int>(0)));
+  // EXPECT_EQ(1ULL, StrictNumeric<size_t>(1));
+  // EXPECT_EQ(1, StrictNumeric<size_t>(1U));
 
   // Test various saturation corner cases.
   EXPECT_EQ(saturated_cast<int>(small_negative),
@@ -572,5 +662,105 @@
   EXPECT_EQ(saturated_cast<int>(double_large), numeric_limits<int>::max());
   EXPECT_EQ(saturated_cast<float>(double_large), double_infinity);
   EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity);
+  EXPECT_EQ(numeric_limits<int>::min(), saturated_cast<int>(double_small_int));
+  EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int));
 }
 
+TEST(SafeNumerics, IsValueInRangeForNumericType) {
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(2));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0xffffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0xffffffff)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000000)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000001)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
+      std::numeric_limits<int64_t>::min()));
+
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(2));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffff));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffffu));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0x80000000u));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0xffffffffu));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x80000000)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0xffffffff)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x100000000)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
+      static_cast<int64_t>(std::numeric_limits<int32_t>::min())));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
+      static_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
+      std::numeric_limits<int64_t>::min()));
+
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(2));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0xffffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0xffffffff)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000000)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000001)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(INT64_C(-1)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
+      std::numeric_limits<int64_t>::min()));
+
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(2));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffff));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x80000000u));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0xffffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x80000000)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0xffffffff)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x100000000)));
+  EXPECT_TRUE(
+      IsValueInRangeForNumericType<int64_t>(INT64_C(0x7fffffffffffffff)));
+  EXPECT_TRUE(
+      IsValueInRangeForNumericType<int64_t>(UINT64_C(0x7fffffffffffffff)));
+  EXPECT_FALSE(
+      IsValueInRangeForNumericType<int64_t>(UINT64_C(0x8000000000000000)));
+  EXPECT_FALSE(
+      IsValueInRangeForNumericType<int64_t>(UINT64_C(0xffffffffffffffff)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+      static_cast<int64_t>(std::numeric_limits<int32_t>::min())));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+      std::numeric_limits<int64_t>::min()));
+}
+
+TEST(SafeNumerics, CompoundNumericOperations) {
+  CheckedNumeric<int> a = 1;
+  CheckedNumeric<int> b = 2;
+  CheckedNumeric<int> c = 3;
+  CheckedNumeric<int> d = 4;
+  a += b;
+  EXPECT_EQ(3, a.ValueOrDie());
+  a -= c;
+  EXPECT_EQ(0, a.ValueOrDie());
+  d /= b;
+  EXPECT_EQ(2, d.ValueOrDie());
+  d *= d;
+  EXPECT_EQ(4, d.ValueOrDie());
+
+  CheckedNumeric<int> too_large = std::numeric_limits<int>::max();
+  EXPECT_TRUE(too_large.IsValid());
+  too_large += d;
+  EXPECT_FALSE(too_large.IsValid());
+  too_large -= d;
+  EXPECT_FALSE(too_large.IsValid());
+  too_large /= d;
+  EXPECT_FALSE(too_large.IsValid());
+}
diff --git a/base/observer_list.h b/base/observer_list.h
index fb6f026..a454430 100644
--- a/base/observer_list.h
+++ b/base/observer_list.h
@@ -51,18 +51,20 @@
 //     }
 //
 //    private:
-//     ObserverList<Observer> observer_list_;
+//     base::ObserverList<Observer> observer_list_;
 //   };
 //
 //
 ///////////////////////////////////////////////////////////////////////////////
 
+namespace base {
+
 template <typename ObserverType>
 class ObserverListThreadSafe;
 
 template <class ObserverType>
 class ObserverListBase
-    : public base::SupportsWeakPtr<ObserverListBase<ObserverType> > {
+    : public SupportsWeakPtr<ObserverListBase<ObserverType>> {
  public:
   // Enumeration of which observers are notified.
   enum NotificationType {
@@ -84,7 +86,7 @@
     ObserverType* GetNext();
 
    private:
-    base::WeakPtr<ObserverListBase<ObserverType> > list_;
+    WeakPtr<ObserverListBase<ObserverType>> list_;
     size_t index_;
     size_t max_index_;
   };
@@ -232,12 +234,14 @@
 #define FOR_EACH_OBSERVER(ObserverType, observer_list, func)             \
   do {                                                                   \
     if ((observer_list).might_have_observers()) {                        \
-      ObserverListBase<ObserverType>::Iterator it_inside_observer_macro( \
+      base::ObserverListBase<ObserverType>::Iterator it_inside_observer_macro( \
           &observer_list);                                               \
       ObserverType* obs;                                                 \
-      while ((obs = it_inside_observer_macro.GetNext()) != nullptr)         \
+      while ((obs = it_inside_observer_macro.GetNext()) != nullptr)      \
         obs->func;                                                       \
     }                                                                    \
   } while (0)
 
+}  // namespace base
+
 #endif  // BASE_OBSERVER_LIST_H_
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
index e0ce0da..e420494 100644
--- a/base/observer_list_threadsafe.h
+++ b/base/observer_list_threadsafe.h
@@ -53,19 +53,22 @@
 //
 ///////////////////////////////////////////////////////////////////////////////
 
+namespace base {
+
 // Forward declaration for ObserverListThreadSafeTraits.
 template <class ObserverType>
 class ObserverListThreadSafe;
 
+namespace internal {
+
 // An UnboundMethod is a wrapper for a method where the actual object is
 // provided at Run dispatch time.
 template <class T, class Method, class Params>
 class UnboundMethod {
  public:
   UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
-    COMPILE_ASSERT(
-        (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
-        badunboundmethodparams);
+    static_assert((internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+                  "bad unbound method params");
   }
   void Run(T* obj) const {
     DispatchToMethod(obj, m_, p_);
@@ -75,10 +78,12 @@
   Params p_;
 };
 
+}  // namespace internal
+
 // This class is used to work around VS2005 not accepting:
 //
 // friend class
-//     base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> >;
+//     base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType>>;
 //
 // Instead of friending the class, we could friend the actual function
 // which calls delete.  However, this ends up being
@@ -93,9 +98,9 @@
 
 template <class ObserverType>
 class ObserverListThreadSafe
-    : public base::RefCountedThreadSafe<
+    : public RefCountedThreadSafe<
         ObserverListThreadSafe<ObserverType>,
-        ObserverListThreadSafeTraits<ObserverType> > {
+        ObserverListThreadSafeTraits<ObserverType>> {
  public:
   typedef typename ObserverList<ObserverType>::NotificationType
       NotificationType;
@@ -109,13 +114,13 @@
   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())
+    if (!MessageLoop::current())
       return;
 
     ObserverList<ObserverType>* list = nullptr;
-    base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
+    PlatformThreadId thread_id = PlatformThread::CurrentId();
     {
-      base::AutoLock lock(list_lock_);
+      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);
@@ -131,9 +136,9 @@
   void RemoveObserver(ObserverType* obs) {
     ObserverListContext* context = nullptr;
     ObserverList<ObserverType>* list = nullptr;
-    base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
+    PlatformThreadId thread_id = PlatformThread::CurrentId();
     {
-      base::AutoLock lock(list_lock_);
+      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
@@ -159,7 +164,7 @@
 
   // Verifies that the list is currently empty (i.e. there are no observers).
   void AssertEmpty() const {
-    base::AutoLock lock(list_lock_);
+    AutoLock lock(list_lock_);
     DCHECK(observer_lists_.empty());
   }
 
@@ -172,16 +177,15 @@
   void Notify(const tracked_objects::Location& from_here,
               Method m,
               const Params&... params) {
-    UnboundMethod<ObserverType, Method, Tuple<Params...>> method(
+    internal::UnboundMethod<ObserverType, Method, Tuple<Params...>> method(
         m, MakeTuple(params...));
 
-    base::AutoLock lock(list_lock_);
+    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<
+          Bind(&ObserverListThreadSafe<ObserverType>::template NotifyWrapper<
                   Method, Tuple<Params...>>,
               this, context, method));
     }
@@ -193,9 +197,9 @@
 
   struct ObserverListContext {
     explicit ObserverListContext(NotificationType type)
-        : task_runner(base::ThreadTaskRunnerHandle::Get()), list(type) {}
+        : task_runner(ThreadTaskRunnerHandle::Get()), list(type) {}
 
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner;
+    scoped_refptr<SingleThreadTaskRunner> task_runner;
     ObserverList<ObserverType> list;
 
    private:
@@ -210,13 +214,14 @@
   // 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) {
+  void NotifyWrapper(
+      ObserverListContext* context,
+      const internal::UnboundMethod<ObserverType, Method, Params>& method) {
     // Check that this list still needs notifications.
     {
-      base::AutoLock lock(list_lock_);
+      AutoLock lock(list_lock_);
       typename ObserversListMap::iterator it =
-          observer_lists_.find(base::PlatformThread::CurrentId());
+          observer_lists_.find(PlatformThread::CurrentId());
 
       // The ObserverList could have been removed already.  In fact, it could
       // have been removed and then re-added!  If the master list's loop
@@ -236,12 +241,12 @@
     // If there are no more observers on the list, we can now delete it.
     if (context->list.size() == 0) {
       {
-        base::AutoLock lock(list_lock_);
+        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());
+            observer_lists_.find(PlatformThread::CurrentId());
         if (it != observer_lists_.end() && it->second == context)
           observer_lists_.erase(it);
       }
@@ -252,14 +257,16 @@
   // 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*>
+  typedef std::map<PlatformThreadId, ObserverListContext*>
       ObserversListMap;
 
-  mutable base::Lock list_lock_;  // Protects the observer_lists_.
+  mutable Lock list_lock_;  // Protects the observer_lists_.
   ObserversListMap observer_lists_;
   const NotificationType type_;
 
   DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
 };
 
+}  // namespace base
+
 #endif  // BASE_OBSERVER_LIST_THREADSAFE_H_
diff --git a/base/path_service.cc b/base/path_service.cc
index 3c437ee..97a0ce5 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -17,27 +17,25 @@
 #include "base/logging.h"
 #include "base/synchronization/lock.h"
 
-using base::FilePath;
-using base::MakeAbsoluteFilePath;
-
 namespace base {
-  bool PathProvider(int key, FilePath* result);
+
+bool PathProvider(int key, FilePath* result);
+
 #if defined(OS_WIN)
-  bool PathProviderWin(int key, FilePath* result);
+bool PathProviderWin(int key, FilePath* result);
 #elif defined(OS_MACOSX)
-  bool PathProviderMac(int key, FilePath* result);
+bool PathProviderMac(int key, FilePath* result);
 #elif defined(OS_ANDROID)
-  bool PathProviderAndroid(int key, FilePath* result);
+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);
+// 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;
+typedef 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.
@@ -52,22 +50,22 @@
 };
 
 Provider base_provider = {
-  base::PathProvider,
+  PathProvider,
   NULL,
 #ifndef NDEBUG
-  base::PATH_START,
-  base::PATH_END,
+  PATH_START,
+  PATH_END,
 #endif
   true
 };
 
 #if defined(OS_WIN)
 Provider base_provider_win = {
-  base::PathProviderWin,
+  PathProviderWin,
   &base_provider,
 #ifndef NDEBUG
-  base::PATH_WIN_START,
-  base::PATH_WIN_END,
+  PATH_WIN_START,
+  PATH_WIN_END,
 #endif
   true
 };
@@ -75,11 +73,11 @@
 
 #if defined(OS_MACOSX)
 Provider base_provider_mac = {
-  base::PathProviderMac,
+  PathProviderMac,
   &base_provider,
 #ifndef NDEBUG
-  base::PATH_MAC_START,
-  base::PATH_MAC_END,
+  PATH_MAC_START,
+  PATH_MAC_END,
 #endif
   true
 };
@@ -87,11 +85,11 @@
 
 #if defined(OS_ANDROID)
 Provider base_provider_android = {
-  base::PathProviderAndroid,
+  PathProviderAndroid,
   &base_provider,
 #ifndef NDEBUG
-  base::PATH_ANDROID_START,
-  base::PATH_ANDROID_END,
+  PATH_ANDROID_START,
+  PATH_ANDROID_END,
 #endif
   true
 };
@@ -99,11 +97,11 @@
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
 Provider base_provider_posix = {
-  base::PathProviderPosix,
+  PathProviderPosix,
   &base_provider,
 #ifndef NDEBUG
-  base::PATH_POSIX_START,
-  base::PATH_POSIX_END,
+  PATH_POSIX_START,
+  PATH_POSIX_END,
 #endif
   true
 };
@@ -111,7 +109,7 @@
 
 
 struct PathData {
-  base::Lock lock;
+  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.
@@ -140,7 +138,7 @@
   }
 };
 
-static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
+static LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
 
 static PathData* GetPathData() {
   return g_path_data.Pointer();
@@ -183,15 +181,15 @@
   PathData* path_data = GetPathData();
   DCHECK(path_data);
   DCHECK(result);
-  DCHECK_GE(key, base::DIR_CURRENT);
+  DCHECK_GE(key, DIR_CURRENT);
 
   // special case the current directory because it can never be cached
-  if (key == base::DIR_CURRENT)
-    return base::GetCurrentDirectory(result);
+  if (key == DIR_CURRENT)
+    return GetCurrentDirectory(result);
 
   Provider* provider = NULL;
   {
-    base::AutoLock scoped_lock(path_data->lock);
+    AutoLock scoped_lock(path_data->lock);
     if (LockedGetFromCache(key, path_data, result))
       return true;
 
@@ -224,7 +222,7 @@
   }
   *result = path;
 
-  base::AutoLock scoped_lock(path_data->lock);
+  AutoLock scoped_lock(path_data->lock);
   if (!path_data->cache_disabled)
     path_data->cache[key] = path;
 
@@ -245,7 +243,7 @@
                                             bool create) {
   PathData* path_data = GetPathData();
   DCHECK(path_data);
-  DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key";
+  DCHECK_GT(key, DIR_CURRENT) << "invalid path key";
 
   FilePath file_path = path;
 
@@ -255,8 +253,7 @@
     // 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))
+    if (!PathExists(file_path) && !CreateDirectory(file_path))
       return false;
   }
 
@@ -268,7 +265,7 @@
   }
   DCHECK(file_path.IsAbsolute());
 
-  base::AutoLock scoped_lock(path_data->lock);
+  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.
@@ -284,7 +281,7 @@
   PathData* path_data = GetPathData();
   DCHECK(path_data);
 
-  base::AutoLock scoped_lock(path_data->lock);
+  AutoLock scoped_lock(path_data->lock);
 
   if (path_data->overrides.find(key) == path_data->overrides.end())
     return false;
@@ -315,7 +312,7 @@
   p->key_end = key_end;
 #endif
 
-  base::AutoLock scoped_lock(path_data->lock);
+  AutoLock scoped_lock(path_data->lock);
 
 #ifndef NDEBUG
   Provider *iter = path_data->providers;
@@ -335,7 +332,9 @@
   PathData* path_data = GetPathData();
   DCHECK(path_data);
 
-  base::AutoLock scoped_lock(path_data->lock);
+  AutoLock scoped_lock(path_data->lock);
   path_data->cache.clear();
   path_data->cache_disabled = true;
 }
+
+}  // namespace base
diff --git a/base/path_service.h b/base/path_service.h
index 025550f..c7f1abe 100644
--- a/base/path_service.h
+++ b/base/path_service.h
@@ -13,9 +13,9 @@
 #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.
@@ -29,7 +29,7 @@
   //
   // 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);
+  static bool Get(int key, FilePath* path);
 
   // Overrides the path to a special directory or file.  This cannot be used to
   // change the value of DIR_CURRENT, but that should be obvious.  Also, if the
@@ -44,7 +44,7 @@
   //
   // 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);
+  static bool Override(int key, const FilePath& path);
 
   // This function does the same as PathService::Override but it takes extra
   // parameters:
@@ -56,7 +56,7 @@
   // - |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,
+                                        const FilePath& path,
                                         bool is_absolute,
                                         bool create);
 
@@ -68,7 +68,7 @@
   // 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*);
+  typedef bool (*ProviderFunc)(int, FilePath*);
 
   // Call to register a path provider.  You must specify the range "[key_start,
   // key_end)" of supported path keys.
@@ -80,7 +80,7 @@
   static void DisableCache();
 
  private:
-  friend class base::ScopedPathOverride;
+  friend class ScopedPathOverride;
   FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride);
 
   // Removes an override for a special directory or file. Returns true if there
@@ -89,4 +89,9 @@
   static bool RemoveOverride(int key);
 };
 
+}  // namespace base
+
+// TODO(brettw) Convert all callers to using the base namespace and remove this.
+using base::PathService;
+
 #endif  // BASE_PATH_SERVICE_H_
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc
index 7551d67..569c0f4 100644
--- a/base/path_service_unittest.cc
+++ b/base/path_service_unittest.cc
@@ -18,12 +18,14 @@
 #include "base/win/windows_version.h"
 #endif
 
+namespace base {
+
 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;
+  FilePath path;
   bool result = PathService::Get(dir_type, &path);
 
   // Some paths might not exist on some platforms in which case confirming
@@ -32,25 +34,25 @@
 #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)
+  if (dir_type == 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)
+  if (dir_type == DIR_USER_DESKTOP)
     check_path_exists = false;
 #endif
 #if defined(OS_WIN)
-  if (dir_type == base::DIR_TASKBAR_PINS) {
+  if (dir_type == 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 (dir_type != DIR_EXE && dir_type != DIR_MODULE &&
+      dir_type != FILE_EXE && dir_type != FILE_MODULE) {
     if (path.ReferencesParent())
       return false;
   }
@@ -58,8 +60,7 @@
   if (path.ReferencesParent())
     return false;
 #endif
-  return result && !path.empty() && (!check_path_exists ||
-                                     base::PathExists(path));
+  return result && !path.empty() && (!check_path_exists || PathExists(path));
 }
 
 #if defined(OS_WIN)
@@ -67,7 +68,7 @@
 // of Windows. Checks that the function fails and that the returned path is
 // empty.
 bool ReturnsInvalidPath(int dir_type) {
-  base::FilePath path;
+  FilePath path;
   bool result = PathService::Get(dir_type, &path);
   return !result && path.empty();
 }
@@ -84,21 +85,21 @@
 // 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) {
+  for (int key = PATH_START + 1; key < PATH_END; ++key) {
 #if defined(OS_ANDROID)
-    if (key == base::FILE_MODULE || key == base::DIR_USER_DESKTOP ||
-        key == base::DIR_HOME)
+    if (key == FILE_MODULE || key == DIR_USER_DESKTOP ||
+        key == DIR_HOME)
       continue;  // Android doesn't implement these.
 #elif defined(OS_IOS)
-    if (key == base::DIR_USER_DESKTOP)
+    if (key == 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) {
+  for (int key = PATH_WIN_START + 1; key < PATH_WIN_END; ++key) {
     bool valid = true;
-    if (key == base::DIR_APP_SHORTCUTS)
+    if (key == DIR_APP_SHORTCUTS)
       valid = base::win::GetVersion() >= base::win::VERSION_WIN8;
 
     if (valid)
@@ -107,16 +108,16 @@
       EXPECT_TRUE(ReturnsInvalidPath(key)) << key;
   }
 #elif defined(OS_MACOSX)
-  for (int key = base::PATH_MAC_START + 1; key < base::PATH_MAC_END; ++key) {
+  for (int key = PATH_MAC_START + 1; key < 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;
+  for (int key = PATH_ANDROID_START + 1; key < 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;
+  for (int key = PATH_POSIX_START + 1; key < PATH_POSIX_END;
        ++key) {
     EXPECT_PRED1(ReturnsValidPath, key);
   }
@@ -127,32 +128,32 @@
 // are supposed to do.
 TEST_F(PathServiceTest, Override) {
   int my_special_key = 666;
-  base::ScopedTempDir temp_dir;
+  ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  base::FilePath fake_cache_dir(temp_dir.path().AppendASCII("cache"));
+  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));
+  EXPECT_TRUE(PathExists(fake_cache_dir));
 
-  base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("cache2"));
+  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_FALSE(PathExists(fake_cache_dir2));
   EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
                                                      fake_cache_dir2,
                                                      false,
                                                      true));
-  EXPECT_TRUE(base::PathExists(fake_cache_dir2));
+  EXPECT_TRUE(PathExists(fake_cache_dir2));
 
 #if defined(OS_POSIX)
-  base::FilePath non_existent(
-      base::MakeAbsoluteFilePath(temp_dir.path()).AppendASCII("non_existent"));
+  FilePath non_existent(
+      MakeAbsoluteFilePath(temp_dir.path()).AppendASCII("non_existent"));
   EXPECT_TRUE(non_existent.IsAbsolute());
-  EXPECT_FALSE(base::PathExists(non_existent));
+  EXPECT_FALSE(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
@@ -169,8 +170,8 @@
                                                      true,
                                                      false));
   // Check that the path has been overridden and no directory was created.
-  EXPECT_FALSE(base::PathExists(non_existent));
-  base::FilePath path;
+  EXPECT_FALSE(PathExists(non_existent));
+  FilePath path;
   EXPECT_TRUE(PathService::Get(my_special_key, &path));
   EXPECT_EQ(non_existent, path);
 #endif
@@ -179,62 +180,62 @@
 // Check if multiple overrides can co-exist.
 TEST_F(PathServiceTest, OverrideMultiple) {
   int my_special_key = 666;
-  base::ScopedTempDir temp_dir;
+  ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  base::FilePath fake_cache_dir1(temp_dir.path().AppendASCII("1"));
+  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));
+  EXPECT_TRUE(PathExists(fake_cache_dir1));
+  ASSERT_EQ(1, WriteFile(fake_cache_dir1.AppendASCII("t1"), ".", 1));
 
-  base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("2"));
+  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));
+  EXPECT_TRUE(PathExists(fake_cache_dir2));
+  ASSERT_EQ(1, WriteFile(fake_cache_dir2.AppendASCII("t2"), ".", 1));
 
-  base::FilePath result;
+  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(PathExists(result.AppendASCII("t1")));
   EXPECT_TRUE(PathService::Get(my_special_key + 1, &result));
-  EXPECT_TRUE(base::PathExists(result.AppendASCII("t2")));
+  EXPECT_TRUE(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);
+  PathService::RemoveOverride(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));
+  FilePath original_user_data_dir;
+  EXPECT_TRUE(PathService::Get(DIR_TEMP, &original_user_data_dir));
+  EXPECT_FALSE(PathService::RemoveOverride(DIR_TEMP));
 
-  base::ScopedTempDir temp_dir;
+  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_TRUE(PathService::Override(DIR_TEMP, temp_dir.path()));
+  FilePath new_user_data_dir;
+  EXPECT_TRUE(PathService::Get(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_TRUE(PathService::RemoveOverride(DIR_TEMP));
+  EXPECT_TRUE(PathService::Get(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;
+  FilePath programfiles_dir;
 #if defined(_WIN64)
   // 64-bit on 64-bit.
-  EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+  EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES,
       &programfiles_dir));
   EXPECT_EQ(programfiles_dir.value(),
       FILE_PATH_LITERAL("C:\\Program Files"));
-  EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+  EXPECT_TRUE(PathService::Get(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,
+  EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432,
       &programfiles_dir));
   EXPECT_EQ(programfiles_dir.value(),
       FILE_PATH_LITERAL("C:\\Program Files"));
@@ -242,29 +243,29 @@
   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,
+    EXPECT_TRUE(PathService::Get(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,
+    EXPECT_TRUE(PathService::Get(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,
+    EXPECT_TRUE(PathService::Get(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,
+    EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES,
         &programfiles_dir));
     EXPECT_EQ(programfiles_dir.value(),
         FILE_PATH_LITERAL("C:\\Program Files"));
-    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+    EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILESX86,
         &programfiles_dir));
     EXPECT_EQ(programfiles_dir.value(),
         FILE_PATH_LITERAL("C:\\Program Files"));
-    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+    EXPECT_TRUE(PathService::Get(DIR_PROGRAM_FILES6432,
         &programfiles_dir));
     EXPECT_EQ(programfiles_dir.value(),
         FILE_PATH_LITERAL("C:\\Program Files"));
@@ -272,3 +273,5 @@
 #endif
 }
 #endif
+
+}  // namespace base
diff --git a/base/pickle.cc b/base/pickle.cc
index 112ddc3..489c7f8 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -7,11 +7,12 @@
 #include <stdlib.h>
 
 #include <algorithm>  // for max()
+#include <limits>
 
-//------------------------------------------------------------------------------
+#include "base/bits.h"
+#include "base/macros.h"
 
-using base::char16;
-using base::string16;
+namespace base {
 
 // static
 const int Pickle::kPayloadUnit = 64;
@@ -37,7 +38,7 @@
 }
 
 inline void PickleIterator::Advance(size_t size) {
-  size_t aligned_size = AlignInt(size, sizeof(uint32_t));
+  size_t aligned_size = bits::Align(size, sizeof(uint32_t));
   if (end_index_ - read_index_ < aligned_size) {
     read_index_ = end_index_;
   } else {
@@ -152,7 +153,7 @@
   return true;
 }
 
-bool PickleIterator::ReadStringPiece(base::StringPiece* result) {
+bool PickleIterator::ReadStringPiece(StringPiece* result) {
   int len;
   if (!ReadInt(&len))
     return false;
@@ -160,7 +161,7 @@
   if (!read_from)
     return false;
 
-  *result = base::StringPiece(read_from, len);
+  *result = StringPiece(read_from, len);
   return true;
 }
 
@@ -176,7 +177,7 @@
   return true;
 }
 
-bool PickleIterator::ReadStringPiece16(base::StringPiece16* result) {
+bool PickleIterator::ReadStringPiece16(StringPiece16* result) {
   int len;
   if (!ReadInt(&len))
     return false;
@@ -184,8 +185,7 @@
   if (!read_from)
     return false;
 
-  *result = base::StringPiece16(reinterpret_cast<const char16*>(read_from),
-                                len);
+  *result = StringPiece16(reinterpret_cast<const char16*>(read_from), len);
   return true;
 }
 
@@ -214,13 +214,15 @@
       header_size_(sizeof(Header)),
       capacity_after_header_(0),
       write_offset_(0) {
+  static_assert((Pickle::kPayloadUnit & (Pickle::kPayloadUnit - 1)) == 0,
+                "Pickle::kPayloadUnit must be a power of two");
   Resize(kPayloadUnit);
   header_->payload_size = 0;
 }
 
 Pickle::Pickle(int header_size)
     : header_(NULL),
-      header_size_(AlignInt(header_size, sizeof(uint32))),
+      header_size_(bits::Align(header_size, sizeof(uint32))),
       capacity_after_header_(0),
       write_offset_(0) {
   DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
@@ -240,7 +242,7 @@
   if (header_size_ > static_cast<unsigned int>(data_len))
     header_size_ = 0;
 
-  if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
+  if (header_size_ != bits::Align(header_size_, sizeof(uint32)))
     header_size_ = 0;
 
   // If there is anything wrong with the data, we're not going to use it.
@@ -253,9 +255,8 @@
       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);
+  Resize(other.header_->payload_size);
+  memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
 }
 
 Pickle::~Pickle() {
@@ -284,14 +285,14 @@
   return *this;
 }
 
-bool Pickle::WriteString(const base::StringPiece& value) {
+bool Pickle::WriteString(const StringPiece& value) {
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
   return WriteBytes(value.data(), static_cast<int>(value.size()));
 }
 
-bool Pickle::WriteString16(const base::StringPiece16& value) {
+bool Pickle::WriteString16(const StringPiece16& value) {
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
@@ -309,7 +310,7 @@
 }
 
 void Pickle::Reserve(size_t length) {
-  size_t data_len = AlignInt(length, sizeof(uint32));
+  size_t data_len = bits::Align(length, sizeof(uint32));
   DCHECK_GE(data_len, length);
 #ifdef ARCH_CPU_64_BITS
   DCHECK_LE(data_len, kuint32max);
@@ -321,30 +322,58 @@
 }
 
 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);
+  capacity_after_header_ = bits::Align(new_capacity, kPayloadUnit);
+  void* p = realloc(header_, GetTotalAllocatedSize());
   CHECK(p);
   header_ = reinterpret_cast<Header*>(p);
-  capacity_after_header_ = new_capacity;
+}
+
+size_t Pickle::GetTotalAllocatedSize() const {
+  if (capacity_after_header_ == kCapacityReadOnly)
+    return 0;
+  return header_size_ + capacity_after_header_;
 }
 
 // static
 const char* Pickle::FindNext(size_t header_size,
                              const char* start,
                              const char* end) {
-  DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
+  size_t pickle_size = 0;
+  if (!PeekNext(header_size, start, end, &pickle_size))
+    return NULL;
+
+  if (pickle_size > static_cast<size_t>(end - start))
+    return NULL;
+
+  return start + pickle_size;
+}
+
+// static
+bool Pickle::PeekNext(size_t header_size,
+                      const char* start,
+                      const char* end,
+                      size_t* pickle_size) {
+  DCHECK_EQ(header_size, bits::Align(header_size, sizeof(uint32)));
+  DCHECK_GE(header_size, sizeof(Header));
   DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
 
   size_t length = static_cast<size_t>(end - start);
   if (length < sizeof(Header))
-    return NULL;
+    return false;
 
   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;
+  if (length < header_size)
+    return false;
+
+  if (hdr->payload_size > std::numeric_limits<size_t>::max() - header_size) {
+    // If payload_size causes an overflow, we return maximum possible
+    // pickle size to indicate that.
+    *pickle_size = std::numeric_limits<size_t>::max();
+  } else {
+    *pickle_size = header_size + hdr->payload_size;
+  }
+  return true;
 }
 
 template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
@@ -359,7 +388,7 @@
   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));
+  size_t data_len = bits::Align(length, sizeof(uint32));
   DCHECK_GE(data_len, length);
 #ifdef ARCH_CPU_64_BITS
   DCHECK_LE(data_len, kuint32max);
@@ -367,7 +396,11 @@
   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));
+    size_t new_capacity = capacity_after_header_ * 2;
+    const size_t kPickleHeapAlign = 4096;
+    if (new_capacity > kPickleHeapAlign)
+      new_capacity = bits::Align(new_capacity, kPickleHeapAlign) - kPayloadUnit;
+    Resize(std::max(new_capacity, new_size));
   }
 
   char* write = mutable_payload() + write_offset_;
@@ -376,3 +409,5 @@
   header_->payload_size = static_cast<uint32>(new_size);
   write_offset_ = new_size;
 }
+
+}  // namespace base
diff --git a/base/pickle.h b/base/pickle.h
index 9589e2a..22b8055 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -15,6 +15,8 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_piece.h"
 
+namespace base {
+
 class Pickle;
 
 // PickleIterator reads data from a Pickle. The Pickle object must remain valid
@@ -41,10 +43,10 @@
   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;
+  bool ReadStringPiece(StringPiece* result) WARN_UNUSED_RESULT;
+  bool ReadString16(string16* result) WARN_UNUSED_RESULT;
   // The StringPiece16 data will only be valid for the lifetime of the message.
-  bool ReadStringPiece16(base::StringPiece16* result) WARN_UNUSED_RESULT;
+  bool ReadStringPiece16(StringPiece16* result) WARN_UNUSED_RESULT;
 
   // A pointer to the data will be placed in |*data|, and the length will be
   // placed in |*length|. The pointer placed into |*data| points into the
@@ -72,11 +74,6 @@
   }
 
  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);
@@ -151,12 +148,18 @@
   // Performs a deep copy.
   Pickle& operator=(const Pickle& other);
 
-  // Returns the size of the Pickle's data.
+  // Returns the number of bytes written in the Pickle, including the header.
   size_t size() const { return header_size_ + header_->payload_size; }
 
   // Returns the data for this Pickle.
   const void* data() const { return header_; }
 
+  // Returns the effective memory capacity of this Pickle, that is, the total
+  // number of bytes currently dynamically allocated or 0 in the case of a
+  // read-only Pickle. This should be used only for diagnostic / profiling
+  // purposes.
+  size_t GetTotalAllocatedSize() const;
+
   // Methods for adding to the payload of the Pickle.  These values are
   // appended to the end of the Pickle's payload.  When reading values from a
   // Pickle, it is important to read them in the order in which they were added
@@ -199,8 +202,8 @@
   bool WriteDouble(double value) {
     return WritePOD(value);
   }
-  bool WriteString(const base::StringPiece& value);
-  bool WriteString16(const base::StringPiece16& value);
+  bool WriteString(const StringPiece& value);
+  bool WriteString16(const StringPiece16& value);
   // "Data" is a blob with a length. When you read it out you will be given the
   // length. See also WriteBytes.
   bool WriteData(const char* data, int length);
@@ -262,17 +265,24 @@
   // 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);
 
+  // Parse pickle header and return total size of the pickle. Data range
+  // doesn't need to contain entire pickle.
+  // Returns true if pickle header was found and parsed. Callers must check
+  // returned |pickle_size| for sanity (against maximum message size, etc).
+  // NOTE: when function successfully parses a header, but encounters an
+  // overflow during pickle size calculation, it sets |pickle_size| to the
+  // maximum size_t value and returns true.
+  static bool PeekNext(size_t header_size,
+                       const char* range_start,
+                       const char* range_end,
+                       size_t* pickle_size);
+
   // The allocation granularity of the payload.
   static const int kPayloadUnit;
 
@@ -298,10 +308,15 @@
   }
   inline void WriteBytesCommon(const void* data, size_t length);
 
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, DeepCopyResize);
   FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, PeekNext);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, PeekNextOverflow);
   FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
   FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader);
   FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextOverflow);
 };
 
+}  // namespace base
+
 #endif  // BASE_PICKLE_H_
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
index a2c405c..f58e7ec 100644
--- a/base/pickle_unittest.cc
+++ b/base/pickle_unittest.cc
@@ -11,8 +11,7 @@
 #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 base {
 
 namespace {
 
@@ -29,10 +28,10 @@
 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 string16 teststring16(ASCIIToUTF16("Hello, world"));
 const char testrawstring[] = "Hello new world"; // Test raw string writing
 // Test raw char16 writing, assumes UTF16 encoding is ANSI for alpha chars.
-const base::char16 testrawstring16[] = {'A', 'l', 'o', 'h', 'a', 0};
+const char16 testrawstring16[] = {'A', 'l', 'o', 'h', 'a', 0};
 const char testdata[] = "AAA\0BBB\0";
 const int testdatalen = arraysize(testdata) - 1;
 
@@ -86,15 +85,15 @@
   EXPECT_TRUE(iter.ReadString(&outstring));
   EXPECT_EQ(teststring, outstring);
 
-  base::string16 outstring16;
+  string16 outstring16;
   EXPECT_TRUE(iter.ReadString16(&outstring16));
   EXPECT_EQ(teststring16, outstring16);
 
-  base::StringPiece outstringpiece;
+  StringPiece outstringpiece;
   EXPECT_TRUE(iter.ReadStringPiece(&outstringpiece));
   EXPECT_EQ(testrawstring, outstringpiece);
 
-  base::StringPiece16 outstringpiece16;
+  StringPiece16 outstringpiece16;
   EXPECT_TRUE(iter.ReadStringPiece16(&outstringpiece16));
   EXPECT_EQ(testrawstring16, outstringpiece16);
 
@@ -208,7 +207,7 @@
 
 TEST(PickleTest, ZeroLenStr16) {
   Pickle pickle;
-  EXPECT_TRUE(pickle.WriteString16(base::string16()));
+  EXPECT_TRUE(pickle.WriteString16(string16()));
 
   PickleIterator iter(pickle);
   std::string outstr;
@@ -230,10 +229,92 @@
   EXPECT_TRUE(pickle.WriteInt(-1));
 
   PickleIterator iter(pickle);
-  base::string16 outstr;
+  string16 outstr;
   EXPECT_FALSE(iter.ReadString16(&outstr));
 }
 
+TEST(PickleTest, PeekNext) {
+  struct CustomHeader : base::Pickle::Header {
+    int cookies[10];
+  };
+
+  Pickle pickle(sizeof(CustomHeader));
+
+  EXPECT_TRUE(pickle.WriteString("Goooooooooooogle"));
+
+  const char* pickle_data = static_cast<const char*>(pickle.data());
+
+  size_t pickle_size;
+
+  // Data range doesn't contain header
+  EXPECT_FALSE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader) - 1,
+      &pickle_size));
+
+  // Data range contains header
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader),
+      &pickle_size));
+  EXPECT_EQ(pickle_size, pickle.size());
+
+  // Data range contains header and some other data
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader) + 1,
+      &pickle_size));
+  EXPECT_EQ(pickle_size, pickle.size());
+
+  // Data range contains full pickle
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + pickle.size(),
+      &pickle_size));
+  EXPECT_EQ(pickle_size, pickle.size());
+}
+
+TEST(PickleTest, PeekNextOverflow) {
+  struct CustomHeader : base::Pickle::Header {
+    int cookies[10];
+  };
+
+  CustomHeader header;
+
+  // Check if we can wrap around at all
+  if (sizeof(size_t) > sizeof(header.payload_size))
+    return;
+
+  const char* pickle_data = reinterpret_cast<const char*>(&header);
+
+  size_t pickle_size;
+
+  // Wrapping around is detected and reported as maximum size_t value
+  header.payload_size = static_cast<uint32_t>(
+      1 - static_cast<int32_t>(sizeof(CustomHeader)));
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader),
+      &pickle_size));
+  EXPECT_EQ(pickle_size, std::numeric_limits<size_t>::max());
+
+  // Ridiculous pickle sizes are fine (callers are supposed to
+  // verify them)
+  header.payload_size =
+      std::numeric_limits<uint32_t>::max() / 2 - sizeof(CustomHeader);
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader),
+      &pickle_size));
+  EXPECT_EQ(pickle_size, std::numeric_limits<uint32_t>::max() / 2);
+}
+
 TEST(PickleTest, FindNext) {
   Pickle pickle;
   EXPECT_TRUE(pickle.WriteInt(1));
@@ -428,3 +509,19 @@
   memcpy(&outdata, outdata_char, sizeof(outdata));
   EXPECT_EQ(data, outdata);
 }
+
+// Checks that when a pickle is deep-copied, the result is not larger than
+// needed.
+TEST(PickleTest, DeepCopyResize) {
+  Pickle pickle;
+  while (pickle.capacity_after_header() != pickle.payload_size())
+    pickle.WriteBool(true);
+
+  // Make a deep copy.
+  Pickle pickle2(pickle);
+
+  // Check that there isn't any extraneous capacity.
+  EXPECT_EQ(pickle.capacity_after_header(), pickle2.capacity_after_header());
+}
+
+}  // namespace base
diff --git a/base/port.h b/base/port.h
deleted file mode 100644
index 56c4d4e..0000000
--- a/base/port.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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/safe_strerror_posix.cc b/base/posix/safe_strerror.cc
similarity index 97%
rename from base/safe_strerror_posix.cc
rename to base/posix/safe_strerror.cc
index 9da7aee..e80e8f8 100644
--- a/base/safe_strerror_posix.cc
+++ b/base/posix/safe_strerror.cc
@@ -10,13 +10,16 @@
 #undef _GNU_SOURCE
 #endif
 
-#include "build/build_config.h"
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 
+#include "build/build_config.h"
+
+namespace base {
+
 #define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL))
 
 #if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
@@ -117,3 +120,5 @@
   safe_strerror_r(err, buf, sizeof(buf));
   return std::string(buf);
 }
+
+}  // namespace base
diff --git a/base/safe_strerror_posix.h b/base/posix/safe_strerror.h
similarity index 90%
rename from base/safe_strerror_posix.h
rename to base/posix/safe_strerror.h
index 2f77d84..862a750 100644
--- a/base/safe_strerror_posix.h
+++ b/base/posix/safe_strerror.h
@@ -2,13 +2,15 @@
 // 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_
+#ifndef BASE_POSIX_SAFE_STRERROR_H_
+#define BASE_POSIX_SAFE_STRERROR_H_
 
 #include <string>
 
 #include "base/base_export.h"
 
+namespace base {
+
 // BEFORE using anything from this file, first look at PLOG and friends in
 // logging.h and use them instead if applicable.
 //
@@ -35,4 +37,6 @@
 // allocate a string.
 BASE_EXPORT std::string safe_strerror(int err);
 
-#endif  // BASE_SAFE_STRERROR_POSIX_H_
+}  // namespace base
+
+#endif  // BASE_POSIX_SAFE_STRERROR_H_
diff --git a/base/posix/unix_domain_socket_linux.cc b/base/posix/unix_domain_socket_linux.cc
index 16d8eaa..62c930f 100644
--- a/base/posix/unix_domain_socket_linux.cc
+++ b/base/posix/unix_domain_socket_linux.cc
@@ -21,13 +21,15 @@
 #include <sys/uio.h>
 #endif
 
+namespace base {
+
 const size_t UnixDomainSocket::kMaxFileDescriptors = 16;
 
 #if !defined(OS_NACL_NONSFI)
 // Creates a connected pair of UNIX-domain SOCK_SEQPACKET sockets, and passes
 // ownership of the newly allocated file descriptors to |one| and |two|.
 // Returns true on success.
-static bool CreateSocketPair(base::ScopedFD* one, base::ScopedFD* two) {
+static bool CreateSocketPair(ScopedFD* one, ScopedFD* two) {
   int raw_socks[2];
   if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks) == -1)
     return false;
@@ -84,7 +86,7 @@
 ssize_t UnixDomainSocket::RecvMsg(int fd,
                                   void* buf,
                                   size_t length,
-                                  ScopedVector<base::ScopedFD>* fds) {
+                                  ScopedVector<ScopedFD>* fds) {
   return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, NULL);
 }
 
@@ -92,8 +94,8 @@
 ssize_t UnixDomainSocket::RecvMsgWithPid(int fd,
                                          void* buf,
                                          size_t length,
-                                         ScopedVector<base::ScopedFD>* fds,
-                                         base::ProcessId* pid) {
+                                         ScopedVector<ScopedFD>* fds,
+                                         ProcessId* pid) {
   return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid);
 }
 
@@ -102,8 +104,8 @@
                                            void* buf,
                                            size_t length,
                                            int flags,
-                                           ScopedVector<base::ScopedFD>* fds,
-                                           base::ProcessId* out_pid) {
+                                           ScopedVector<ScopedFD>* fds,
+                                           ProcessId* out_pid) {
   fds->clear();
 
   struct msghdr msg = {};
@@ -128,7 +130,7 @@
 
   int* wire_fds = NULL;
   unsigned wire_fds_len = 0;
-  base::ProcessId pid = -1;
+  ProcessId pid = -1;
 
   if (msg.msg_controllen > 0) {
     struct cmsghdr* cmsg;
@@ -163,7 +165,7 @@
 
   if (wire_fds) {
     for (unsigned i = 0; i < wire_fds_len; ++i)
-      fds->push_back(new base::ScopedFD(wire_fds[i]));
+      fds->push_back(new ScopedFD(wire_fds[i]));
   }
 
   if (out_pid) {
@@ -201,7 +203,7 @@
                                                const Pickle& request) {
   // This socketpair is only used for the IPC and is cleaned up before
   // returning.
-  base::ScopedFD recv_sock, send_sock;
+  ScopedFD recv_sock, send_sock;
   if (!CreateSocketPair(&recv_sock, &send_sock))
     return -1;
 
@@ -217,7 +219,7 @@
   // return EOF instead of hanging.
   send_sock.reset();
 
-  ScopedVector<base::ScopedFD> recv_fds;
+  ScopedVector<ScopedFD> recv_fds;
   // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the
   // sender might get a SIGPIPE.
   const ssize_t reply_len = RecvMsgWithFlags(
@@ -239,3 +241,5 @@
   return reply_len;
 }
 #endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace base
diff --git a/base/posix/unix_domain_socket_linux.h b/base/posix/unix_domain_socket_linux.h
index 142cb14..94da4b4 100644
--- a/base/posix/unix_domain_socket_linux.h
+++ b/base/posix/unix_domain_socket_linux.h
@@ -14,6 +14,8 @@
 #include "base/memory/scoped_vector.h"
 #include "base/process/process_handle.h"
 
+namespace base {
+
 class Pickle;
 
 class BASE_EXPORT UnixDomainSocket {
@@ -40,7 +42,7 @@
   static ssize_t RecvMsg(int fd,
                          void* msg,
                          size_t length,
-                         ScopedVector<base::ScopedFD>* fds);
+                         ScopedVector<ScopedFD>* fds);
 
   // Same as RecvMsg above, but also returns the sender's process ID (as seen
   // from the caller's namespace).  However, before using this function to
@@ -49,8 +51,8 @@
   static ssize_t RecvMsgWithPid(int fd,
                                 void* msg,
                                 size_t length,
-                                ScopedVector<base::ScopedFD>* fds,
-                                base::ProcessId* pid);
+                                ScopedVector<ScopedFD>* fds,
+                                ProcessId* pid);
 
 #if !defined(OS_NACL_NONSFI)
   // Perform a sendmsg/recvmsg pair.
@@ -92,8 +94,10 @@
                                   void* msg,
                                   size_t length,
                                   int flags,
-                                  ScopedVector<base::ScopedFD>* fds,
-                                  base::ProcessId* pid);
+                                  ScopedVector<ScopedFD>* fds,
+                                  ProcessId* pid);
 };
 
+}  // namespace base
+
 #endif  // BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
diff --git a/base/posix/unix_domain_socket_linux_unittest.cc b/base/posix/unix_domain_socket_linux_unittest.cc
index c05141c..175ec52 100644
--- a/base/posix/unix_domain_socket_linux_unittest.cc
+++ b/base/posix/unix_domain_socket_linux_unittest.cc
@@ -40,7 +40,7 @@
            static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL), request));
 
   // Receive the message.
-  ScopedVector<base::ScopedFD> message_fds;
+  ScopedVector<ScopedFD> message_fds;
   uint8_t buffer[16];
   ASSERT_EQ(static_cast<int>(request.size()),
             UnixDomainSocket::RecvMsg(fds[0], buffer, sizeof(buffer),
@@ -82,8 +82,8 @@
 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]);
+  ScopedFD recv_sock(fds[0]);
+  ScopedFD send_sock(fds[1]);
 
   ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
 
@@ -94,8 +94,8 @@
   // 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;
+  ProcessId sender_pid;
+  ScopedVector<ScopedFD> fd_vec;
   const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
       recv_sock.get(), buf, sizeof(buf), &fd_vec, &sender_pid);
   ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
@@ -109,8 +109,8 @@
 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]);
+  ScopedFD recv_sock(fds[0]);
+  ScopedFD send_sock(fds[1]);
 
   ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
 
@@ -123,8 +123,8 @@
   // 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;
+  ProcessId sender_pid;
+  ScopedVector<ScopedFD> recv_fds;
   const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
       recv_sock.get(), buf, sizeof(buf), &recv_fds, &sender_pid);
   ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
@@ -139,16 +139,16 @@
 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]);
+  ScopedFD recv_sock(fds[0]);
+  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;
+  ProcessId sender_pid;
+  ScopedVector<ScopedFD> recv_fds;
   const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
       recv_sock.get(), &ch, sizeof(ch), &recv_fds, &sender_pid);
   ASSERT_EQ(0, nread);
diff --git a/base/power_monitor/power_monitor.cc b/base/power_monitor/power_monitor.cc
index 98c9c68..1033299 100644
--- a/base/power_monitor/power_monitor.cc
+++ b/base/power_monitor/power_monitor.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "base/power_monitor/power_monitor.h"
+
+#include <utility>
+
 #include "base/power_monitor/power_monitor_source.h"
 
 namespace base {
@@ -11,7 +14,7 @@
 
 PowerMonitor::PowerMonitor(scoped_ptr<PowerMonitorSource> source)
     : observers_(new ObserverListThreadSafe<PowerObserver>()),
-      source_(source.Pass()) {
+      source_(std::move(source)) {
   DCHECK(!g_power_monitor);
   g_power_monitor = this;
 }
diff --git a/base/power_monitor/power_monitor_device_source.h b/base/power_monitor/power_monitor_device_source.h
index 29f17c2..fa0b039 100644
--- a/base/power_monitor/power_monitor_device_source.h
+++ b/base/power_monitor/power_monitor_device_source.h
@@ -102,7 +102,7 @@
 #endif
 
 #if defined(ENABLE_BATTERY_MONITORING)
-  base::OneShotTimer<PowerMonitorDeviceSource> delayed_battery_check_;
+  base::OneShotTimer delayed_battery_check_;
 #endif
 
 #if defined(OS_WIN)
diff --git a/base/power_monitor/power_monitor_device_source_android.cc b/base/power_monitor/power_monitor_device_source_android.cc
index 4d9eb52..9671c30 100644
--- a/base/power_monitor/power_monitor_device_source_android.cc
+++ b/base/power_monitor/power_monitor_device_source_android.cc
@@ -19,15 +19,15 @@
 namespace android {
 
 // Native implementation of PowerMonitor.java.
-void OnBatteryChargingChanged(JNIEnv* env, jclass clazz) {
+void OnBatteryChargingChanged(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   ProcessPowerEventHelper(PowerMonitorSource::POWER_STATE_EVENT);
 }
 
-void OnMainActivityResumed(JNIEnv* env, jclass clazz) {
+void OnMainActivityResumed(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   ProcessPowerEventHelper(PowerMonitorSource::RESUME_EVENT);
 }
 
-void OnMainActivitySuspended(JNIEnv* env, jclass clazz) {
+void OnMainActivitySuspended(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   ProcessPowerEventHelper(PowerMonitorSource::SUSPEND_EVENT);
 }
 
diff --git a/base/power_monitor/power_monitor_device_source_mac.mm b/base/power_monitor/power_monitor_device_source_mac.mm
index 61e4396..8c48117 100644
--- a/base/power_monitor/power_monitor_device_source_mac.mm
+++ b/base/power_monitor/power_monitor_device_source_mac.mm
@@ -10,8 +10,8 @@
 #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>
+#include <IOKit/pwr_mgt/IOPMLib.h>
 
 namespace base {
 
diff --git a/base/power_monitor/power_monitor_device_source_win.cc b/base/power_monitor/power_monitor_device_source_win.cc
index 0e199dc..b8b16e1 100644
--- a/base/power_monitor/power_monitor_device_source_win.cc
+++ b/base/power_monitor/power_monitor_device_source_win.cc
@@ -5,7 +5,6 @@
 #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 {
@@ -99,11 +98,6 @@
     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);
diff --git a/base/prefs/OWNERS b/base/prefs/OWNERS
index 97ab695..2d87038 100644
--- a/base/prefs/OWNERS
+++ b/base/prefs/OWNERS
@@ -1,5 +1,4 @@
 battre@chromium.org
 bauerb@chromium.org
 gab@chromium.org
-mnissler@chromium.org
 pam@chromium.org
diff --git a/base/prefs/default_pref_store.cc b/base/prefs/default_pref_store.cc
index 92abba1..b08ef7a 100644
--- a/base/prefs/default_pref_store.cc
+++ b/base/prefs/default_pref_store.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "base/prefs/default_pref_store.h"
+
+#include <utility>
+
 #include "base/logging.h"
 
 using base::Value;
@@ -29,7 +32,7 @@
 void DefaultPrefStore::SetDefaultValue(const std::string& key,
                                        scoped_ptr<Value> value) {
   DCHECK(!GetValue(key, NULL));
-  prefs_.SetValue(key, value.release());
+  prefs_.SetValue(key, std::move(value));
 }
 
 void DefaultPrefStore::ReplaceDefaultValue(const std::string& key,
@@ -37,7 +40,7 @@
   const Value* old_value = NULL;
   GetValue(key, &old_value);
   bool notify = !old_value->Equals(value.get());
-  prefs_.SetValue(key, value.release());
+  prefs_.SetValue(key, std::move(value));
   if (notify)
     FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
 }
diff --git a/base/prefs/default_pref_store.h b/base/prefs/default_pref_store.h
index 26462da..e736b06 100644
--- a/base/prefs/default_pref_store.h
+++ b/base/prefs/default_pref_store.h
@@ -44,7 +44,7 @@
 
   PrefValueMap prefs_;
 
-  ObserverList<PrefStore::Observer, true> observers_;
+  base::ObserverList<PrefStore::Observer, true> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(DefaultPrefStore);
 };
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc
index da545b8..ae15cd7 100644
--- a/base/prefs/json_pref_store.cc
+++ b/base/prefs/json_pref_store.cc
@@ -5,6 +5,7 @@
 #include "base/prefs/json_pref_store.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -60,16 +61,12 @@
     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
@@ -87,9 +84,9 @@
         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;
   }
+  if (!value->IsType(base::Value::TYPE_DICTIONARY))
+    return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
   return PersistentPrefStore::PREF_READ_ERROR_NONE;
 }
 
@@ -122,7 +119,7 @@
   scoped_ptr<JsonPrefStore::ReadResult> read_result(
       new JsonPrefStore::ReadResult);
   JSONFileValueDeserializer deserializer(path);
-  read_result->value.reset(deserializer.Deserialize(&error_code, &error_msg));
+  read_result->value = 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());
@@ -130,7 +127,7 @@
   if (read_result->error == PersistentPrefStore::PREF_READ_ERROR_NONE)
     RecordJsonDataSizeHistogram(path, deserializer.get_last_read_size());
 
-  return read_result.Pass();
+  return read_result;
 }
 
 }  // namespace
@@ -147,27 +144,26 @@
 }
 
 JsonPrefStore::JsonPrefStore(
-    const base::FilePath& filename,
+    const base::FilePath& pref_filename,
     const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
     scoped_ptr<PrefFilter> pref_filter)
-    : JsonPrefStore(filename,
+    : JsonPrefStore(pref_filename,
                     base::FilePath(),
                     sequenced_task_runner,
-                    pref_filter.Pass()) {
-}
+                    std::move(pref_filter)) {}
 
 JsonPrefStore::JsonPrefStore(
-    const base::FilePath& filename,
-    const base::FilePath& alternate_filename,
+    const base::FilePath& pref_filename,
+    const base::FilePath& pref_alternate_filename,
     const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
     scoped_ptr<PrefFilter> pref_filter)
-    : path_(filename),
-      alternate_path_(alternate_filename),
+    : path_(pref_filename),
+      alternate_path_(pref_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()),
+      writer_(pref_filename, sequenced_task_runner),
+      pref_filter_(std::move(pref_filter)),
       initialized_(false),
       filtering_in_progress_(false),
       pending_lossy_write_(false),
@@ -180,7 +176,7 @@
                              const base::Value** result) const {
   DCHECK(CalledOnValidThread());
 
-  base::Value* tmp = NULL;
+  base::Value* tmp = nullptr;
   if (!prefs_->Get(key, &tmp))
     return false;
 
@@ -221,31 +217,29 @@
 }
 
 void JsonPrefStore::SetValue(const std::string& key,
-                             base::Value* value,
+                             scoped_ptr<base::Value> value,
                              uint32 flags) {
   DCHECK(CalledOnValidThread());
 
   DCHECK(value);
-  scoped_ptr<base::Value> new_value(value);
-  base::Value* old_value = NULL;
+  base::Value* old_value = nullptr;
   prefs_->Get(key, &old_value);
   if (!old_value || !value->Equals(old_value)) {
-    prefs_->Set(key, new_value.Pass());
+    prefs_->Set(key, std::move(value));
     ReportValueChanged(key, flags);
   }
 }
 
 void JsonPrefStore::SetValueSilently(const std::string& key,
-                                     base::Value* value,
+                                     scoped_ptr<base::Value> value,
                                      uint32 flags) {
   DCHECK(CalledOnValidThread());
 
   DCHECK(value);
-  scoped_ptr<base::Value> new_value(value);
-  base::Value* old_value = NULL;
+  base::Value* old_value = nullptr;
   prefs_->Get(key, &old_value);
   if (!old_value || !value->Equals(old_value)) {
-    prefs_->Set(key, new_value.Pass());
+    prefs_->Set(key, std::move(value));
     ScheduleWrite(flags);
   }
 }
@@ -253,14 +247,14 @@
 void JsonPrefStore::RemoveValue(const std::string& key, uint32 flags) {
   DCHECK(CalledOnValidThread());
 
-  if (prefs_->RemovePath(key, NULL))
+  if (prefs_->RemovePath(key, nullptr))
     ReportValueChanged(key, flags);
 }
 
 void JsonPrefStore::RemoveValueSilently(const std::string& key, uint32 flags) {
   DCHECK(CalledOnValidThread());
 
-  prefs_->RemovePath(key, NULL);
+  prefs_->RemovePath(key, nullptr);
   ScheduleWrite(flags);
 }
 
@@ -303,13 +297,17 @@
 
   // Schedule a write for any lossy writes that are outstanding to ensure that
   // they get flushed when this function is called.
-  if (pending_lossy_write_)
-    writer_.ScheduleWrite(this);
+  SchedulePendingLossyWrites();
 
   if (writer_.HasPendingWrite() && !read_only_)
     writer_.DoScheduledWrite();
 }
 
+void JsonPrefStore::SchedulePendingLossyWrites() {
+  if (pending_lossy_write_)
+    writer_.ScheduleWrite(this);
+}
+
 void JsonPrefStore::ReportValueChanged(const std::string& key, uint32 flags) {
   DCHECK(CalledOnValidThread());
 
@@ -356,7 +354,6 @@
       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;
@@ -364,13 +361,6 @@
         // 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;
@@ -384,9 +374,10 @@
             &JsonPrefStore::FinalizeFileRead, AsWeakPtr(),
             initialization_successful));
     pref_filter_->FilterOnLoad(post_filter_on_load_callback,
-                               unfiltered_prefs.Pass());
+                               std::move(unfiltered_prefs));
   } else {
-    FinalizeFileRead(initialization_successful, unfiltered_prefs.Pass(), false);
+    FinalizeFileRead(initialization_successful, std::move(unfiltered_prefs),
+                     false);
   }
 }
 
@@ -426,7 +417,7 @@
     return;
   }
 
-  prefs_ = prefs.Pass();
+  prefs_ = std::move(prefs);
 
   initialized_ = true;
 
diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h
index ef260eb..d9dcdbd 100644
--- a/base/prefs/json_pref_store.h
+++ b/base/prefs/json_pref_store.h
@@ -15,7 +15,6 @@
 #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"
@@ -84,10 +83,10 @@
   // PersistentPrefStore overrides:
   bool GetMutableValue(const std::string& key, base::Value** result) override;
   void SetValue(const std::string& key,
-                base::Value* value,
+                scoped_ptr<base::Value> value,
                 uint32 flags) override;
   void SetValueSilently(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override;
   void RemoveValue(const std::string& key, uint32 flags) override;
   bool ReadOnly() const override;
@@ -98,6 +97,7 @@
   PrefReadError ReadPrefs() override;
   void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
   void CommitPendingWrite() override;
+  void SchedulePendingLossyWrites() override;
   void ReportValueChanged(const std::string& key, uint32 flags) override;
 
   // Just like RemoveValue(), but doesn't notify observers. Used when doing some
@@ -208,7 +208,7 @@
   base::ImportantFileWriter writer_;
 
   scoped_ptr<PrefFilter> pref_filter_;
-  ObserverList<PrefStore::Observer, true> observers_;
+  base::ObserverList<PrefStore::Observer, true> observers_;
 
   scoped_ptr<ReadErrorDelegate> error_delegate_;
 
diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc
index 67a8adb..d850292 100644
--- a/base/prefs/json_pref_store_unittest.cc
+++ b/base/prefs/json_pref_store_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "base/prefs/json_pref_store.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -73,12 +75,12 @@
     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();
+  intercepted_prefs_ = std::move(pref_store_contents);
 }
 
 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_.Run(std::move(intercepted_prefs_), false);
   post_filter_on_load_callback_.Reset();
 }
 
@@ -192,7 +194,8 @@
   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()),
+  pref_store->SetValue(kSomeDirectory,
+                       make_scoped_ptr(new StringValue(some_path.value())),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
   EXPECT_TRUE(actual->GetAsString(&path));
@@ -204,7 +207,8 @@
   EXPECT_TRUE(actual->GetAsBoolean(&boolean));
   EXPECT_TRUE(boolean);
 
-  pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false),
+  pref_store->SetValue(kNewWindowsInTabs,
+                       make_scoped_ptr(new FundamentalValue(false)),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
   EXPECT_TRUE(actual->GetAsBoolean(&boolean));
@@ -214,15 +218,16 @@
   int integer = 0;
   EXPECT_TRUE(actual->GetAsInteger(&integer));
   EXPECT_EQ(20, integer);
-  pref_store->SetValue(kMaxTabs, new FundamentalValue(10),
+  pref_store->SetValue(kMaxTabs, make_scoped_ptr(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);
+  pref_store->SetValue(
+      kLongIntPref,
+      make_scoped_ptr(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;
@@ -312,9 +317,9 @@
       pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
   // Set some keys with empty values.
-  pref_store->SetValue("list", new base::ListValue,
+  pref_store->SetValue("list", make_scoped_ptr(new base::ListValue),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-  pref_store->SetValue("dict", new base::DictionaryValue,
+  pref_store->SetValue("dict", make_scoped_ptr(new base::DictionaryValue),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   // Write to file.
@@ -343,9 +348,9 @@
   scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
       pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
 
-  base::DictionaryValue* dict = new base::DictionaryValue;
+  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
   dict->SetString("key", "value");
-  pref_store->SetValue("dict", dict,
+  pref_store->SetValue("dict", std::move(dict),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   pref_store->RemoveValue("dict.key",
@@ -389,8 +394,9 @@
       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());
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, message_loop_.task_runner(),
+                        std::move(intercepting_pref_filter));
 
   ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
             pref_store->ReadPrefs());
@@ -434,8 +440,9 @@
       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());
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, message_loop_.task_runner(),
+                        std::move(intercepting_pref_filter));
 
   MockPrefStoreObserver mock_observer;
   pref_store->AddObserver(&mock_observer);
@@ -845,7 +852,8 @@
 
   // Set a normal pref and check that it gets scheduled to be written.
   ASSERT_FALSE(file_writer->HasPendingWrite());
-  pref_store->SetValue("normal", new base::StringValue("normal"),
+  pref_store->SetValue("normal",
+                       make_scoped_ptr(new base::StringValue("normal")),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   ASSERT_TRUE(file_writer->HasPendingWrite());
   file_writer->DoScheduledWrite();
@@ -854,14 +862,15 @@
 
   // Set a lossy pref and check that it is not scheduled to be written.
   // SetValue/RemoveValue.
-  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
                        WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
   pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
 
   // SetValueSilently/RemoveValueSilently.
-  pref_store->SetValueSilently("lossy", new base::StringValue("lossy"),
+  pref_store->SetValueSilently("lossy",
+                               make_scoped_ptr(new base::StringValue("lossy")),
                                WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
   pref_store->RemoveValueSilently("lossy",
@@ -869,7 +878,7 @@
   ASSERT_FALSE(file_writer->HasPendingWrite());
 
   // ReportValueChanged.
-  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
                        WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
   pref_store->ReportValueChanged("lossy",
@@ -890,12 +899,13 @@
 
   // Set a lossy pref and check that it is not scheduled to be written.
   ASSERT_FALSE(file_writer->HasPendingWrite());
-  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
                        WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_FALSE(file_writer->HasPendingWrite());
 
   // Set a normal pref and check that it is scheduled to be written.
-  pref_store->SetValue("normal", new base::StringValue("normal"),
+  pref_store->SetValue("normal",
+                       make_scoped_ptr(new base::StringValue("normal")),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   ASSERT_TRUE(file_writer->HasPendingWrite());
 
@@ -912,12 +922,13 @@
 
   // Set a normal pref and check that it is scheduled to be written.
   ASSERT_FALSE(file_writer->HasPendingWrite());
-  pref_store->SetValue("normal", new base::StringValue("normal"),
+  pref_store->SetValue("normal",
+                       make_scoped_ptr(new base::StringValue("normal")),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   ASSERT_TRUE(file_writer->HasPendingWrite());
 
   // Set a lossy pref and check that the write is still scheduled.
-  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
                        WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
   ASSERT_TRUE(file_writer->HasPendingWrite());
 
@@ -928,4 +939,24 @@
   ASSERT_FALSE(file_writer->HasPendingWrite());
 }
 
+TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
+  scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+  ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+
+  // Set a lossy pref and check that it is not scheduled to be written.
+  pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
+                       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+
+  // Schedule pending lossy writes and check that it is scheduled.
+  pref_store->SchedulePendingLossyWrites();
+  ASSERT_TRUE(file_writer->HasPendingWrite());
+
+  // Call CommitPendingWrite and check that the lossy pref is there with the
+  // last value set above.
+  pref_store->CommitPendingWrite();
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+  ASSERT_EQ("{\"lossy\":\"lossy\"}", GetTestFileContents());
+}
+
 }  // namespace base
diff --git a/base/prefs/overlay_user_pref_store.cc b/base/prefs/overlay_user_pref_store.cc
index e93dffd..f386cef 100644
--- a/base/prefs/overlay_user_pref_store.cc
+++ b/base/prefs/overlay_user_pref_store.cc
@@ -4,6 +4,8 @@
 
 #include "base/prefs/overlay_user_pref_store.h"
 
+#include <utility>
+
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 
@@ -58,31 +60,31 @@
     return false;
 
   *result = underlay_value->DeepCopy();
-  overlay_.SetValue(key, *result);
+  overlay_.SetValue(key, make_scoped_ptr(*result));
   return true;
 }
 
 void OverlayUserPrefStore::SetValue(const std::string& key,
-                                    base::Value* value,
+                                    scoped_ptr<base::Value> value,
                                     uint32 flags) {
   if (!ShallBeStoredInOverlay(key)) {
-    underlay_->SetValue(GetUnderlayKey(key), value, flags);
+    underlay_->SetValue(GetUnderlayKey(key), std::move(value), flags);
     return;
   }
 
-  if (overlay_.SetValue(key, value))
+  if (overlay_.SetValue(key, std::move(value)))
     ReportValueChanged(key, flags);
 }
 
 void OverlayUserPrefStore::SetValueSilently(const std::string& key,
-                                            base::Value* value,
+                                            scoped_ptr<base::Value> value,
                                             uint32 flags) {
   if (!ShallBeStoredInOverlay(key)) {
-    underlay_->SetValueSilently(GetUnderlayKey(key), value, flags);
+    underlay_->SetValueSilently(GetUnderlayKey(key), std::move(value), flags);
     return;
   }
 
-  overlay_.SetValue(key, value);
+  overlay_.SetValue(key, std::move(value));
 }
 
 void OverlayUserPrefStore::RemoveValue(const std::string& key, uint32 flags) {
@@ -121,6 +123,10 @@
   // We do not write our content intentionally.
 }
 
+void OverlayUserPrefStore::SchedulePendingLossyWrites() {
+  underlay_->SchedulePendingLossyWrites();
+}
+
 void OverlayUserPrefStore::ReportValueChanged(const std::string& key,
                                               uint32 flags) {
   FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
diff --git a/base/prefs/overlay_user_pref_store.h b/base/prefs/overlay_user_pref_store.h
index 04c309d..737b426 100644
--- a/base/prefs/overlay_user_pref_store.h
+++ b/base/prefs/overlay_user_pref_store.h
@@ -40,10 +40,10 @@
   // Methods of PersistentPrefStore.
   bool GetMutableValue(const std::string& key, base::Value** result) override;
   void SetValue(const std::string& key,
-                base::Value* value,
+                scoped_ptr<base::Value> value,
                 uint32 flags) override;
   void SetValueSilently(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override;
   void RemoveValue(const std::string& key, uint32 flags) override;
   bool ReadOnly() const override;
@@ -51,6 +51,7 @@
   PrefReadError ReadPrefs() override;
   void ReadPrefsAsync(ReadErrorDelegate* delegate) override;
   void CommitPendingWrite() override;
+  void SchedulePendingLossyWrites() override;
   void ReportValueChanged(const std::string& key, uint32 flags) override;
 
   // Methods of PrefStore::Observer.
@@ -74,7 +75,7 @@
   // an in-memory PrefStore that is not persisted to disk.
   bool ShallBeStoredInOverlay(const std::string& key) const;
 
-  ObserverList<PrefStore::Observer, true> observers_;
+  base::ObserverList<PrefStore::Observer, true> observers_;
   PrefValueMap overlay_;
   scoped_refptr<PersistentPrefStore> underlay_;
   NamesMap overlay_to_underlay_names_map_;
diff --git a/base/prefs/overlay_user_pref_store_unittest.cc b/base/prefs/overlay_user_pref_store_unittest.cc
index 06b4ec9..bf5e6a5 100644
--- a/base/prefs/overlay_user_pref_store_unittest.cc
+++ b/base/prefs/overlay_user_pref_store_unittest.cc
@@ -48,22 +48,22 @@
   overlay_->AddObserver(&obs);
 
   // Check that underlay first value is reported.
-  underlay_->SetValue(overlay_key, new FundamentalValue(42),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(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),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(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),
+  overlay_->SetValue(overlay_key, make_scoped_ptr(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),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(45)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 
@@ -78,16 +78,17 @@
   obs.VerifyAndResetChangedKey(overlay_key);
 
   // Check respecting of silence.
-  overlay_->SetValueSilently(overlay_key, new FundamentalValue(46),
+  overlay_->SetValueSilently(overlay_key,
+                             make_scoped_ptr(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),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(47)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-  overlay_->SetValue(overlay_key, new FundamentalValue(48),
+  overlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(48)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 }
@@ -97,7 +98,7 @@
   EXPECT_FALSE(overlay_->GetValue(overlay_key, &value));
   EXPECT_FALSE(underlay_->GetValue(overlay_key, &value));
 
-  underlay_->SetValue(overlay_key, new FundamentalValue(42),
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(42)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   // Value shines through:
@@ -107,7 +108,7 @@
   EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
   EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
 
-  overlay_->SetValue(overlay_key, new FundamentalValue(43),
+  overlay_->SetValue(overlay_key, make_scoped_ptr(new FundamentalValue(43)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
@@ -129,7 +130,7 @@
 
 // Check that GetMutableValue does not return the dictionary of the underlay.
 TEST_F(OverlayUserPrefStoreTest, ModifyDictionaries) {
-  underlay_->SetValue(overlay_key, new DictionaryValue,
+  underlay_->SetValue(overlay_key, make_scoped_ptr(new DictionaryValue),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 
   Value* modify = NULL;
@@ -159,12 +160,12 @@
   const Value* value = NULL;
 
   // Check that underlay first value is reported.
-  underlay_->SetValue(regular_key, new FundamentalValue(42),
+  underlay_->SetValue(regular_key, make_scoped_ptr(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),
+  underlay_->SetValue(regular_key, make_scoped_ptr(new FundamentalValue(43)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(regular_key);
 
@@ -173,7 +174,7 @@
   EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
 
   // Check that overwriting change in overlay is reported.
-  overlay_->SetValue(regular_key, new FundamentalValue(44),
+  overlay_->SetValue(regular_key, make_scoped_ptr(new FundamentalValue(44)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(regular_key);
 
@@ -193,16 +194,17 @@
   EXPECT_FALSE(underlay_->GetValue(regular_key, &value));
 
   // Check respecting of silence.
-  overlay_->SetValueSilently(regular_key, new FundamentalValue(46),
+  overlay_->SetValueSilently(regular_key,
+                             make_scoped_ptr(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),
+  underlay_->SetValue(regular_key, make_scoped_ptr(new FundamentalValue(47)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-  overlay_->SetValue(regular_key, new FundamentalValue(48),
+  overlay_->SetValue(regular_key, make_scoped_ptr(new FundamentalValue(48)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 }
@@ -216,12 +218,14 @@
 
   // 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),
+  underlay_->SetValue(mapped_underlay_key,
+                      make_scoped_ptr(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),
+  underlay_->SetValue(mapped_underlay_key,
+                      make_scoped_ptr(new FundamentalValue(43)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(mapped_overlay_key);
 
@@ -233,7 +237,8 @@
   EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
 
   // Check that overwriting change in overlay is reported.
-  overlay_->SetValue(mapped_overlay_key, new FundamentalValue(44),
+  overlay_->SetValue(mapped_overlay_key,
+                     make_scoped_ptr(new FundamentalValue(44)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   obs.VerifyAndResetChangedKey(mapped_overlay_key);
 
@@ -247,7 +252,8 @@
   EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
 
   // Check that hidden underlay change is not reported.
-  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(45),
+  underlay_->SetValue(mapped_underlay_key,
+                      make_scoped_ptr(new FundamentalValue(45)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 
@@ -266,16 +272,19 @@
   EXPECT_FALSE(overlay_->GetValue(mapped_underlay_key, &value));
 
   // Check respecting of silence.
-  overlay_->SetValueSilently(mapped_overlay_key, new FundamentalValue(46),
+  overlay_->SetValueSilently(mapped_overlay_key,
+                             make_scoped_ptr(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),
+  underlay_->SetValue(mapped_underlay_key,
+                      make_scoped_ptr(new FundamentalValue(47)),
                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
-  overlay_->SetValue(mapped_overlay_key, new FundamentalValue(48),
+  overlay_->SetValue(mapped_overlay_key,
+                     make_scoped_ptr(new FundamentalValue(48)),
                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   EXPECT_TRUE(obs.changed_keys.empty());
 }
diff --git a/base/prefs/persistent_pref_store.h b/base/prefs/persistent_pref_store.h
index e70e2a6..89c7a71 100644
--- a/base/prefs/persistent_pref_store.h
+++ b/base/prefs/persistent_pref_store.h
@@ -33,9 +33,6 @@
     // 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
   };
 
@@ -67,6 +64,12 @@
   // Lands any pending writes to disk.
   virtual void CommitPendingWrite() = 0;
 
+  // Schedule a write if there is any lossy data pending. Unlike
+  // CommitPendingWrite() this does not immediately sync to disk, instead it
+  // triggers an eventual write if there is lossy data pending and if there
+  // isn't one scheduled already.
+  virtual void SchedulePendingLossyWrites() = 0;
+
  protected:
   ~PersistentPrefStore() override {}
 };
diff --git a/base/prefs/pref_member.cc b/base/prefs/pref_member.cc
index 64c3d6a..934237d 100644
--- a/base/prefs/pref_member.cc
+++ b/base/prefs/pref_member.cc
@@ -4,6 +4,8 @@
 
 #include "base/prefs/pref_member.h"
 
+#include <utility>
+
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/location.h"
@@ -56,7 +58,7 @@
   // Load the value from preferences if it hasn't been loaded so far.
   if (!internal())
     UpdateValueFromPref(base::Closure());
-  internal()->MoveToThread(task_runner.Pass());
+  internal()->MoveToThread(std::move(task_runner));
 }
 
 void PrefMemberBase::OnPreferenceChanged(PrefService* service,
@@ -124,7 +126,7 @@
 void PrefMemberBase::Internal::MoveToThread(
     scoped_refptr<SingleThreadTaskRunner> task_runner) {
   CheckOnCorrectThread();
-  thread_task_runner_ = task_runner.Pass();
+  thread_task_runner_ = std::move(task_runner);
 }
 
 bool PrefMemberVectorStringUpdate(const base::Value& value,
diff --git a/base/prefs/pref_notifier_impl.h b/base/prefs/pref_notifier_impl.h
index cfd46ff..cbf025c 100644
--- a/base/prefs/pref_notifier_impl.h
+++ b/base/prefs/pref_notifier_impl.h
@@ -47,10 +47,10 @@
   // 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::ObserverList<PrefObserver> PrefObserverList;
   typedef base::hash_map<std::string, PrefObserverList*> PrefObserverMap;
 
-  typedef std::list<base::Callback<void(bool)> > PrefInitObserverList;
+  typedef std::list<base::Callback<void(bool)>> PrefInitObserverList;
 
   const PrefObserverMap* pref_observers() const { return &pref_observers_; }
 
diff --git a/base/prefs/pref_service.cc b/base/prefs/pref_service.cc
index 6e1d58c..7741306 100644
--- a/base/prefs/pref_service.cc
+++ b/base/prefs/pref_service.cc
@@ -5,6 +5,7 @@
 #include "base/prefs/pref_service.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
@@ -106,6 +107,11 @@
   user_pref_store_->CommitPendingWrite();
 }
 
+void PrefService::SchedulePendingLossyWrites() {
+  DCHECK(CalledOnValidThread());
+  user_pref_store_->SchedulePendingLossyWrites();
+}
+
 bool PrefService::GetBoolean(const std::string& path) const {
   DCHECK(CalledOnValidThread());
 
@@ -192,7 +198,7 @@
   for (const auto& it : *pref_registry_) {
     out->Set(it.first, GetPreferenceValue(it.first)->CreateDeepCopy());
   }
-  return out.Pass();
+  return out;
 }
 
 scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValuesOmitDefaults()
@@ -205,7 +211,7 @@
       continue;
     out->Set(it.first, pref->GetValue()->CreateDeepCopy());
   }
-  return out.Pass();
+  return out;
 }
 
 scoped_ptr<base::DictionaryValue>
@@ -217,7 +223,7 @@
     DCHECK(value);
     out->SetWithoutPathExpansion(it.first, value->CreateDeepCopy());
   }
-  return out.Pass();
+  return out;
 }
 
 const PrefService::Preference* PrefService::FindPreference(
@@ -466,7 +472,8 @@
     } else {
       NOTREACHED();
     }
-    user_pref_store_->SetValueSilently(path, value, GetWriteFlags(pref));
+    user_pref_store_->SetValueSilently(path, make_scoped_ptr(value),
+                                       GetWriteFlags(pref));
   }
   return value;
 }
@@ -493,7 +500,7 @@
     return;
   }
 
-  user_pref_store_->SetValue(path, owned_value.release(), GetWriteFlags(pref));
+  user_pref_store_->SetValue(path, std::move(owned_value), GetWriteFlags(pref));
 }
 
 void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
diff --git a/base/prefs/pref_service.h b/base/prefs/pref_service.h
index 1fc6c12..25c2f8b 100644
--- a/base/prefs/pref_service.h
+++ b/base/prefs/pref_service.h
@@ -165,6 +165,12 @@
   // immediately (basically, during shutdown).
   void CommitPendingWrite();
 
+  // Schedule a write if there is any lossy data pending. Unlike
+  // CommitPendingWrite() this does not immediately sync to disk, instead it
+  // triggers an eventual write if there is lossy data pending and if there
+  // isn't one scheduled already.
+  void SchedulePendingLossyWrites();
+
   // Returns true if the preference for the given preference name is available
   // and is managed.
   bool IsManagedPreference(const std::string& pref_name) const;
diff --git a/base/prefs/pref_service_factory.cc b/base/prefs/pref_service_factory.cc
index 8caf073..2380a86 100644
--- a/base/prefs/pref_service_factory.cc
+++ b/base/prefs/pref_service_factory.cc
@@ -59,7 +59,7 @@
                       pref_registry,
                       read_error_callback_,
                       async_));
-  return pref_service.Pass();
+  return pref_service;
 }
 
 }  // namespace base
diff --git a/base/prefs/pref_service_unittest.cc b/base/prefs/pref_service_unittest.cc
index 262d7e9..2506b1d 100644
--- a/base/prefs/pref_service_unittest.cc
+++ b/base/prefs/pref_service_unittest.cc
@@ -239,17 +239,15 @@
   }
 
   void SetValue(const std::string& key,
-                base::Value* value,
+                scoped_ptr<base::Value> value,
                 uint32 flags) override {
     SetLastWriteFlags(flags);
-    delete value;
   }
 
   void SetValueSilently(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override {
     SetLastWriteFlags(flags);
-    delete value;
   }
 
   void RemoveValue(const std::string& key, uint32 flags) override {
diff --git a/base/prefs/pref_value_map.cc b/base/prefs/pref_value_map.cc
index 5f2dc50..2340e3c 100644
--- a/base/prefs/pref_value_map.cc
+++ b/base/prefs/pref_value_map.cc
@@ -5,6 +5,7 @@
 #include "base/prefs/pref_value_map.h"
 
 #include <map>
+#include <utility>
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
@@ -13,60 +14,43 @@
 
 PrefValueMap::PrefValueMap() {}
 
-PrefValueMap::~PrefValueMap() {
-  Clear();
-}
+PrefValueMap::~PrefValueMap() {}
 
 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;
+  const base::Value* got_value = prefs_.get(key);
+  if (value && got_value)
+    *value = got_value;
 
-  if (value)
-    *value = entry->second;
-  return true;
+  return !!got_value;
 }
 
 bool PrefValueMap::GetValue(const std::string& key, base::Value** value) {
-  const Map::const_iterator entry = prefs_.find(key);
-  if (entry == prefs_.end())
-    return false;
+  base::Value* got_value = prefs_.get(key);
+  if (value && got_value)
+    *value = got_value;
 
-  if (value)
-    *value = entry->second;
-  return true;
+  return !!got_value;
 }
 
-bool PrefValueMap::SetValue(const std::string& key, base::Value* value) {
+bool PrefValueMap::SetValue(const std::string& key,
+                            scoped_ptr<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))
+  base::Value* old_value = prefs_.get(key);
+  if (old_value && value->Equals(old_value))
     return false;
 
-  delete entry->second;
-  entry->second = value_ptr.release();
-
+  prefs_.set(key, std::move(value));
   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;
+  return prefs_.erase(key) != 0;
 }
 
 void PrefValueMap::Clear() {
-  STLDeleteValues(&prefs_);
+  prefs_.clear();
 }
 
 void PrefValueMap::Swap(PrefValueMap* other) {
@@ -96,7 +80,7 @@
 }
 
 void PrefValueMap::SetBoolean(const std::string& key, bool value) {
-  SetValue(key, new base::FundamentalValue(value));
+  SetValue(key, make_scoped_ptr(new base::FundamentalValue(value)));
 }
 
 bool PrefValueMap::GetString(const std::string& key,
@@ -107,7 +91,7 @@
 
 void PrefValueMap::SetString(const std::string& key,
                              const std::string& value) {
-  SetValue(key, new base::StringValue(value));
+  SetValue(key, make_scoped_ptr(new base::StringValue(value)));
 }
 
 bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
@@ -116,11 +100,11 @@
 }
 
 void PrefValueMap::SetInteger(const std::string& key, const int value) {
-  SetValue(key, new base::FundamentalValue(value));
+  SetValue(key, make_scoped_ptr(new base::FundamentalValue(value)));
 }
 
 void PrefValueMap::SetDouble(const std::string& key, const double value) {
-  SetValue(key, new base::FundamentalValue(value));
+  SetValue(key, make_scoped_ptr(new base::FundamentalValue(value)));
 }
 
 void PrefValueMap::GetDifferingKeys(
diff --git a/base/prefs/pref_value_map.h b/base/prefs/pref_value_map.h
index 12b30c6..7d43f2b 100644
--- a/base/prefs/pref_value_map.h
+++ b/base/prefs/pref_value_map.h
@@ -9,7 +9,8 @@
 #include <vector>
 
 #include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/base_prefs_export.h"
 
 namespace base {
@@ -19,7 +20,7 @@
 // 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 Map = base::ScopedPtrHashMap<std::string, scoped_ptr<base::Value>>;
   using iterator = Map::iterator;
   using const_iterator = Map::const_iterator;
 
@@ -32,9 +33,9 @@
   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);
+  // Sets a new |value| for |key|. |value| must be non-null. Returns true if the
+  // value changed.
+  bool SetValue(const std::string& key, scoped_ptr<base::Value> value);
 
   // Removes the value for |key| from the map. Returns true if a value was
   // removed.
diff --git a/base/prefs/pref_value_map_unittest.cc b/base/prefs/pref_value_map_unittest.cc
index 82499da..f78c999 100644
--- a/base/prefs/pref_value_map_unittest.cc
+++ b/base/prefs/pref_value_map_unittest.cc
@@ -16,9 +16,9 @@
   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.SetValue("key", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_FALSE(map.SetValue("key", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(map.SetValue("key", make_scoped_ptr(new StringValue("hi mom!"))));
 
   EXPECT_TRUE(map.GetValue("key", &result));
   EXPECT_TRUE(StringValue("hi mom!").Equals(result));
@@ -26,7 +26,7 @@
 
 TEST(PrefValueMapTest, GetAndSetIntegerValue) {
   PrefValueMap map;
-  ASSERT_TRUE(map.SetValue("key", new FundamentalValue(5)));
+  ASSERT_TRUE(map.SetValue("key", make_scoped_ptr(new FundamentalValue(5))));
 
   int int_value = 0;
   EXPECT_TRUE(map.GetInteger("key", &int_value));
@@ -39,7 +39,7 @@
 
 TEST(PrefValueMapTest, SetDoubleValue) {
   PrefValueMap map;
-  ASSERT_TRUE(map.SetValue("key", new FundamentalValue(5.5)));
+  ASSERT_TRUE(map.SetValue("key", make_scoped_ptr(new FundamentalValue(5.5))));
 
   const Value* result = NULL;
   ASSERT_TRUE(map.GetValue("key", &result));
@@ -52,7 +52,7 @@
   PrefValueMap map;
   EXPECT_FALSE(map.RemoveValue("key"));
 
-  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.SetValue("key", make_scoped_ptr(new StringValue("test"))));
   EXPECT_TRUE(map.GetValue("key", NULL));
 
   EXPECT_TRUE(map.RemoveValue("key"));
@@ -63,7 +63,7 @@
 
 TEST(PrefValueMapTest, Clear) {
   PrefValueMap map;
-  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.SetValue("key", make_scoped_ptr(new StringValue("test"))));
   EXPECT_TRUE(map.GetValue("key", NULL));
 
   map.Clear();
@@ -73,9 +73,12 @@
 
 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")));
+  EXPECT_TRUE(
+      reference.SetValue("b", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      reference.SetValue("c", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      reference.SetValue("e", make_scoped_ptr(new StringValue("test"))));
 
   PrefValueMap check;
   std::vector<std::string> differing_paths;
@@ -87,9 +90,9 @@
   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")));
+  EXPECT_TRUE(check.SetValue("a", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(check.SetValue("c", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(check.SetValue("d", make_scoped_ptr(new StringValue("test"))));
 
   reference.GetDifferingKeys(&check, &differing_paths);
   expected_differing_paths.clear();
@@ -102,14 +105,20 @@
 
 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")));
+  EXPECT_TRUE(
+      first_map.SetValue("a", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      first_map.SetValue("b", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      first_map.SetValue("c", make_scoped_ptr(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")));
+  EXPECT_TRUE(
+      second_map.SetValue("d", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      second_map.SetValue("e", make_scoped_ptr(new StringValue("test"))));
+  EXPECT_TRUE(
+      second_map.SetValue("f", make_scoped_ptr(new StringValue("test"))));
 
   first_map.Swap(&second_map);
 
diff --git a/base/prefs/pref_value_store.h b/base/prefs/pref_value_store.h
index 5160115..5b832da 100644
--- a/base/prefs/pref_value_store.h
+++ b/base/prefs/pref_value_store.h
@@ -11,7 +11,6 @@
 
 #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"
@@ -179,13 +178,6 @@
 
   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.
diff --git a/base/prefs/testing_pref_service.h b/base/prefs/testing_pref_service.h
index 7587383..cbc978d 100644
--- a/base/prefs/testing_pref_service.h
+++ b/base/prefs/testing_pref_service.h
@@ -182,7 +182,7 @@
     SetPref(TestingPrefStore* pref_store,
             const std::string& path,
             base::Value* value) {
-  pref_store->SetValue(path, value,
+  pref_store->SetValue(path, make_scoped_ptr(value),
                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
 }
 
diff --git a/base/prefs/testing_pref_store.cc b/base/prefs/testing_pref_store.cc
index 35c9763..a3a7ab5 100644
--- a/base/prefs/testing_pref_store.cc
+++ b/base/prefs/testing_pref_store.cc
@@ -4,6 +4,8 @@
 
 #include "base/prefs/testing_pref_store.h"
 
+#include <utility>
+
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 
@@ -43,18 +45,18 @@
 }
 
 void TestingPrefStore::SetValue(const std::string& key,
-                                base::Value* value,
+                                scoped_ptr<base::Value> value,
                                 uint32 flags) {
-  if (prefs_.SetValue(key, value)) {
+  if (prefs_.SetValue(key, std::move(value))) {
     committed_ = false;
     NotifyPrefValueChanged(key);
   }
 }
 
 void TestingPrefStore::SetValueSilently(const std::string& key,
-                                        base::Value* value,
+                                        scoped_ptr<base::Value> value,
                                         uint32 flags) {
-  if (prefs_.SetValue(key, value))
+  if (prefs_.SetValue(key, std::move(value)))
     committed_ = false;
 }
 
@@ -89,6 +91,8 @@
 
 void TestingPrefStore::CommitPendingWrite() { committed_ = true; }
 
+void TestingPrefStore::SchedulePendingLossyWrites() {}
+
 void TestingPrefStore::SetInitializationCompleted() {
   NotifyInitializationCompleted();
 }
@@ -113,15 +117,18 @@
 
 void TestingPrefStore::SetString(const std::string& key,
                                  const std::string& value) {
-  SetValue(key, new base::StringValue(value), DEFAULT_PREF_WRITE_FLAGS);
+  SetValue(key, make_scoped_ptr(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);
+  SetValue(key, make_scoped_ptr(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);
+  SetValue(key, make_scoped_ptr(new base::FundamentalValue(value)),
+           DEFAULT_PREF_WRITE_FLAGS);
 }
 
 bool TestingPrefStore::GetString(const std::string& key,
diff --git a/base/prefs/testing_pref_store.h b/base/prefs/testing_pref_store.h
index 3de5cac..72e61b3 100644
--- a/base/prefs/testing_pref_store.h
+++ b/base/prefs/testing_pref_store.h
@@ -32,10 +32,10 @@
   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,
+                scoped_ptr<base::Value> value,
                 uint32 flags) override;
   void SetValueSilently(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override;
   void RemoveValue(const std::string& key, uint32 flags) override;
   bool ReadOnly() const override;
@@ -43,6 +43,7 @@
   PersistentPrefStore::PrefReadError ReadPrefs() override;
   void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
   void CommitPendingWrite() override;
+  void SchedulePendingLossyWrites() override;
 
   // Marks the store as having completed initialization.
   void SetInitializationCompleted();
@@ -103,7 +104,7 @@
   bool committed_;
 
   scoped_ptr<ReadErrorDelegate> error_delegate_;
-  ObserverList<PrefStore::Observer, true> observers_;
+  base::ObserverList<PrefStore::Observer, true> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(TestingPrefStore);
 };
diff --git a/base/prefs/value_map_pref_store.cc b/base/prefs/value_map_pref_store.cc
index d850150..078ab28 100644
--- a/base/prefs/value_map_pref_store.cc
+++ b/base/prefs/value_map_pref_store.cc
@@ -5,6 +5,7 @@
 #include "base/prefs/value_map_pref_store.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/stl_util.h"
 #include "base/values.h"
@@ -29,9 +30,9 @@
 }
 
 void ValueMapPrefStore::SetValue(const std::string& key,
-                                 base::Value* value,
+                                 scoped_ptr<base::Value> value,
                                  uint32 flags) {
-  if (prefs_.SetValue(key, value))
+  if (prefs_.SetValue(key, std::move(value)))
     FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
 }
 
@@ -51,9 +52,9 @@
 }
 
 void ValueMapPrefStore::SetValueSilently(const std::string& key,
-                                         base::Value* value,
+                                         scoped_ptr<base::Value> value,
                                          uint32 flags) {
-  prefs_.SetValue(key, value);
+  prefs_.SetValue(key, std::move(value));
 }
 
 ValueMapPrefStore::~ValueMapPrefStore() {}
diff --git a/base/prefs/value_map_pref_store.h b/base/prefs/value_map_pref_store.h
index 86c94bb..badfef7 100644
--- a/base/prefs/value_map_pref_store.h
+++ b/base/prefs/value_map_pref_store.h
@@ -29,13 +29,13 @@
 
   // WriteablePrefStore overrides:
   void SetValue(const std::string& key,
-                base::Value* value,
+                scoped_ptr<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,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) override;
 
  protected:
@@ -47,7 +47,7 @@
  private:
   PrefValueMap prefs_;
 
-  ObserverList<PrefStore::Observer, true> observers_;
+  base::ObserverList<PrefStore::Observer, true> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(ValueMapPrefStore);
 };
diff --git a/base/prefs/writeable_pref_store.h b/base/prefs/writeable_pref_store.h
index d85b4c8..cde3c84 100644
--- a/base/prefs/writeable_pref_store.h
+++ b/base/prefs/writeable_pref_store.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_store.h"
 
 namespace base {
@@ -30,10 +31,10 @@
 
   WriteablePrefStore() {}
 
-  // Sets a |value| for |key| in the store. Assumes ownership of |value|, which
-  // must be non-NULL. |flags| is a bitmask of PrefWriteFlags.
+  // Sets a |value| for |key| in the store. |value| must be non-NULL. |flags| is
+  // a bitmask of PrefWriteFlags.
   virtual void SetValue(const std::string& key,
-                        base::Value* value,
+                        scoped_ptr<base::Value> value,
                         uint32 flags) = 0;
 
   // Removes the value for |key|.
@@ -56,7 +57,7 @@
   // tests rely on the number of notifications generated. |flags| is a bitmask
   // of PrefWriteFlags.
   virtual void SetValueSilently(const std::string& key,
-                                base::Value* value,
+                                scoped_ptr<base::Value> value,
                                 uint32 flags) = 0;
 
  protected:
diff --git a/base/process/BUILD.gn b/base/process/BUILD.gn
index e570647..63d65cd 100644
--- a/base/process/BUILD.gn
+++ b/base/process/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/nacl/config.gni")
+
 source_set("process") {
   sources = [
     "internal_linux.cc",
@@ -22,7 +24,10 @@
     "memory_linux.cc",
     "memory_mac.mm",
     "memory_win.cc",
+    "port_provider_mac.cc",
+    "port_provider_mac.h",
     "process.h",
+    "process_handle.cc",
     "process_handle_freebsd.cc",
     "process_handle_linux.cc",
     "process_handle_mac.cc",
@@ -76,14 +81,10 @@
     set_sources_assignment_filter(sources_assignment_filter)
   }
 
-  if (is_nacl) {
+  if (is_nacl || is_ios) {
     sources -= [
       "kill.cc",
       "kill.h",
-      "kill_posix.cc",
-      "launch.cc",
-      "launch.h",
-      "launch_posix.cc",
       "memory.cc",
       "memory.h",
       "process_iterator.cc",
@@ -92,6 +93,25 @@
       "process_metrics_posix.cc",
       "process_posix.cc",
     ]
+    if (!is_nacl_nonsfi) {
+      sources -= [
+        "kill_posix.cc",
+        "launch.cc",
+        "launch.h",
+        "launch_posix.cc",
+      ]
+    }
+  }
+
+  if (is_nacl) {
+    sources += [ "process_metrics_nacl.cc" ]
+  }
+
+  if (is_ios) {
+    sources += [
+      "memory_stubs.cc",
+      "process_metrics.cc",
+    ]
   }
 
   configs += [ "//base:base_implementation" ]
diff --git a/base/process/internal_linux.cc b/base/process/internal_linux.cc
index d2e9ec5..e6c2119 100644
--- a/base/process/internal_linux.cc
+++ b/base/process/internal_linux.cc
@@ -25,8 +25,8 @@
 
 const char kStatFile[] = "stat";
 
-base::FilePath GetProcPidDir(pid_t pid) {
-  return base::FilePath(kProcDir).Append(IntToString(pid));
+FilePath GetProcPidDir(pid_t pid) {
+  return FilePath(kProcDir).Append(IntToString(pid));
 }
 
 pid_t ProcDirSlotToPid(const char* d_name) {
@@ -97,8 +97,9 @@
                         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);
+  std::vector<std::string> other_stats = SplitString(
+      stats_data.substr(close_parens_idx + 2), " ",
+      base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
   for (size_t i = 0; i < other_stats.size(); ++i)
     proc_stats->push_back(other_stats[i]);
   return true;
@@ -106,7 +107,7 @@
 
 typedef std::map<std::string, std::string> ProcStatMap;
 void ParseProcStat(const std::string& contents, ProcStatMap* output) {
-  base::StringPairs key_value_pairs;
+  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]);
diff --git a/base/process/kill.h b/base/process/kill.h
index af00b03..bb4103f 100644
--- a/base/process/kill.h
+++ b/base/process/kill.h
@@ -26,6 +26,10 @@
   TERMINATION_STATUS_PROCESS_WAS_KILLED,   // e.g. SIGKILL or task manager kill
   TERMINATION_STATUS_PROCESS_CRASHED,      // e.g. Segmentation fault
   TERMINATION_STATUS_STILL_RUNNING,        // child hasn't exited yet
+#if defined(OS_CHROMEOS)
+  // Used for the case when oom-killer kills a process on ChromeOS.
+  TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM,
+#endif
 #if defined(OS_ANDROID)
   // On Android processes are spawned from the system Zygote and we do not get
   // the termination status.  We can't know if the termination was a crash or an
@@ -33,6 +37,7 @@
   // a hint.
   TERMINATION_STATUS_OOM_PROTECTED,        // child was protected from oom kill
 #endif
+  TERMINATION_STATUS_LAUNCH_FAILED,        // child process never launched
   TERMINATION_STATUS_MAX_ENUM
 };
 
diff --git a/base/process/kill_mac.cc b/base/process/kill_mac.cc
index a4e0a14..0110c90 100644
--- a/base/process/kill_mac.cc
+++ b/base/process/kill_mac.cc
@@ -4,6 +4,7 @@
 
 #include "base/process/kill.h"
 
+#include <errno.h>
 #include <signal.h>
 #include <sys/event.h>
 #include <sys/types.h>
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc
index 0e303c6..fd83ae1 100644
--- a/base/process/kill_posix.cc
+++ b/base/process/kill_posix.cc
@@ -4,6 +4,7 @@
 
 #include "base/process/kill.h"
 
+#include <errno.h>
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -50,8 +51,13 @@
       case SIGILL:
       case SIGSEGV:
         return TERMINATION_STATUS_PROCESS_CRASHED;
-      case SIGINT:
       case SIGKILL:
+#if defined(OS_CHROMEOS)
+        // On ChromeOS, only way a process gets kill by SIGKILL
+        // is by oom-killer.
+        return TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM;
+#endif
+      case SIGINT:
       case SIGTERM:
         return TERMINATION_STATUS_PROCESS_WAS_KILLED;
       default:
diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc
index 0da3a26..7cbf948 100644
--- a/base/process/kill_win.cc
+++ b/base/process/kill_win.cc
@@ -57,7 +57,7 @@
 };
 
 TimerExpiredTask::TimerExpiredTask(Process process) : process_(process.Pass()) {
-  watcher_.StartWatching(process_.Handle(), this);
+  watcher_.StartWatchingOnce(process_.Handle(), this);
 }
 
 TimerExpiredTask::~TimerExpiredTask() {
diff --git a/base/process/launch.h b/base/process/launch.h
index 56f27a8..42b8a76 100644
--- a/base/process/launch.h
+++ b/base/process/launch.h
@@ -164,16 +164,6 @@
   // 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)
 };
 
@@ -236,7 +226,7 @@
 
 // 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();
+BASE_EXPORT void RouteStdioToConsole(bool create_console_if_not_found);
 #endif  // defined(OS_WIN)
 
 // Executes the application specified by |cl| and wait for it to exit. Stores
@@ -245,6 +235,10 @@
 // indicating success).
 BASE_EXPORT bool GetAppOutput(const CommandLine& cl, std::string* output);
 
+// Like GetAppOutput, but also includes stderr.
+BASE_EXPORT bool GetAppOutputAndError(const CommandLine& cl,
+                                      std::string* output);
+
 #if defined(OS_WIN)
 // A Windows-specific version of GetAppOutput that takes a command line string
 // instead of a CommandLine object. Useful for situations where you need to
@@ -286,18 +280,13 @@
 // 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)
+#if defined(OS_LINUX) || defined(OS_NACL_NONSFI)
 // A wrapper for clone with fork-like behavior, meaning that it returns the
 // child's pid in the parent and 0 in the child. |flags|, |ptid|, and |ctid| are
 // as in the clone system call (the CLONE_VM flag is not supported).
diff --git a/base/process/launch_mac.cc b/base/process/launch_mac.cc
index ce02475..5895eae 100644
--- a/base/process/launch_mac.cc
+++ b/base/process/launch_mac.cc
@@ -28,21 +28,4 @@
                            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
index 77edc12..f076733 100644
--- a/base/process/launch_posix.cc
+++ b/base/process/launch_posix.cc
@@ -22,7 +22,6 @@
 #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"
@@ -65,6 +64,8 @@
 
 namespace base {
 
+#if !defined(OS_NACL_NONSFI)
+
 namespace {
 
 // Get the process's "environment" (i.e. the thing that setenv/getenv
@@ -188,55 +189,6 @@
 }
 #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).
@@ -439,11 +391,6 @@
       }
     }
 
-    // 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) {
@@ -462,8 +409,6 @@
 
 #if defined(OS_MACOSX)
     RestoreDefaultExceptionHandler();
-    if (!options.replacement_bootstrap_name.empty())
-      ReplaceBootstrapPort(options.replacement_bootstrap_name);
 #endif  // defined(OS_MACOSX)
 
     ResetChildSignalHandlersToDefaults();
@@ -577,7 +522,8 @@
 // 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.
+// environment. If |include_stderr| is true, includes stderr otherwise redirects
+// it 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.
@@ -590,6 +536,7 @@
 static GetAppOutputInternalResult GetAppOutputInternal(
     const std::vector<std::string>& argv,
     char* const envp[],
+    bool include_stderr,
     std::string* output,
     size_t max_output,
     bool do_search_path,
@@ -638,13 +585,10 @@
         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(
+            include_stderr ? pipe_fd[1] : dev_null,
+            STDERR_FILENO, true));
         fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
         // Adding another element here? Remeber to increase the argument to
         // reserve(), above.
@@ -713,11 +657,20 @@
   // 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,
+      argv, NULL, false, output, std::numeric_limits<std::size_t>::max(), true,
       &exit_code);
   return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS;
 }
 
+bool GetAppOutputAndError(const CommandLine& cl, std::string* output) {
+  // Run |execve()| with the current environment and store "unlimited" data.
+  int exit_code;
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      cl.argv(), NULL, true, 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,
@@ -726,7 +679,7 @@
   char* const empty_environ = NULL;
   int exit_code;
   GetAppOutputInternalResult result = GetAppOutputInternal(
-      cl.argv(), &empty_environ, output, max_output, false, &exit_code);
+      cl.argv(), &empty_environ, false, output, max_output, false, &exit_code);
   return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS &&
                                       exit_code == EXIT_SUCCESS);
 }
@@ -736,12 +689,64 @@
                               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);
+      cl.argv(), NULL, false, output, std::numeric_limits<std::size_t>::max(),
+      true, exit_code);
   return result == EXECUTE_SUCCESS;
 }
 
-#if defined(OS_LINUX)
+#endif  // !defined(OS_NACL_NONSFI)
+
+#if defined(OS_LINUX) || defined(OS_NACL_NONSFI)
+namespace {
+
+bool IsRunningOnValgrind() {
+  return RUNNING_ON_VALGRIND;
+}
+
+// This function runs on the stack specified on the clone call. It uses longjmp
+// to switch back to the original stack so the child can return from sys_clone.
+int CloneHelper(void* arg) {
+  jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg);
+  longjmp(*env_ptr, 1);
+
+  // Should not be reached.
+  RAW_CHECK(false);
+  return 1;
+}
+
+// This function is noinline to ensure that stack_buf is below the stack pointer
+// that is saved when setjmp is called below. This is needed because when
+// compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved
+// upwards. See crbug.com/442912 for more details.
+#if defined(ADDRESS_SANITIZER)
+// Disable AddressSanitizer instrumentation for this function to make sure
+// |stack_buf| is allocated on thread stack instead of ASan's fake stack.
+// Under ASan longjmp() will attempt to clean up the area between the old and
+// new stack pointers and print a warning that may confuse the user.
+__attribute__((no_sanitize_address))
+#endif
+NOINLINE pid_t CloneAndLongjmpInChild(unsigned long flags,
+                                      pid_t* ptid,
+                                      pid_t* ctid,
+                                      jmp_buf* env) {
+  // We use the libc clone wrapper instead of making the syscall
+  // directly because making the syscall may fail to update the libc's
+  // internal pid cache. The libc interface unfortunately requires
+  // specifying a new stack, so we use setjmp/longjmp to emulate
+  // fork-like behavior.
+  char stack_buf[PTHREAD_STACK_MIN];
+#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);
+}
+
+}  // anonymous namespace
+
 pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid) {
   const bool clone_tls_used = flags & CLONE_SETTLS;
   const bool invalid_ctid =
@@ -780,6 +785,6 @@
 
   return 0;
 }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_NACL_NONSFI)
 
 }  // namespace base
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc
index ebc19b8..54b0667 100644
--- a/base/process/launch_win.cc
+++ b/base/process/launch_win.cc
@@ -46,9 +46,91 @@
 // process goes away.
 const DWORD kProcessKilledExitCode = 1;
 
+bool GetAppOutputInternal(const StringPiece16& cl,
+                          bool include_stderr,
+                          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 handles to the pipes are 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.
+  start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+  if (include_stderr) {
+    start_info.hStdError = out_write;
+  } else {
+    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);
+
+  int exit_code;
+  base::TerminationStatus status = GetTerminationStatus(
+      proc_info.process_handle(), &exit_code);
+  return status != base::TERMINATION_STATUS_PROCESS_CRASHED &&
+         status != base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
+}
+
 }  // namespace
 
-void RouteStdioToConsole() {
+void RouteStdioToConsole(bool create_console_if_not_found) {
   // Don't change anything if stdout or stderr already point to a
   // valid stream.
   //
@@ -64,8 +146,22 @@
   // 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 (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) {
+    // _fileno was broken for SUBSYSTEM:WINDOWS from VS2010 to VS2012/2013.
+    // http://crbug.com/358267. Confirm that the underlying HANDLE is valid
+    // before aborting.
+
+    // This causes NaCl tests to hang on XP for reasons unclear, perhaps due
+    // to not being able to inherit handles. Since it's only for debugging,
+    // and redirecting still works, punt for now.
+    if (base::win::GetVersion() < base::win::VERSION_VISTA)
+      return;
+
+    intptr_t stdout_handle = _get_osfhandle(_fileno(stdout));
+    intptr_t stderr_handle = _get_osfhandle(_fileno(stderr));
+    if (stdout_handle >= 0 || stderr_handle >= 0)
+      return;
+  }
 
   if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
     unsigned int result = GetLastError();
@@ -76,10 +172,14 @@
     // 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();
+    if (create_console_if_not_found) {
+      // 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();
+    } else {
+      return;
+    }
   }
 
   // Arbitrary byte count to use when buffering output lines.  More
@@ -238,7 +338,7 @@
   const string16 file = cmdline.GetProgram().value();
   const string16 arguments = cmdline.GetArgumentsString();
 
-  SHELLEXECUTEINFO shex_info = {0};
+  SHELLEXECUTEINFO shex_info = {};
   shex_info.cbSize = sizeof(shex_info);
   shex_info.fMask = SEE_MASK_NOCLOSEPROCESS;
   shex_info.hwnd = GetActiveWindow();
@@ -261,7 +361,7 @@
 }
 
 bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) {
-  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0};
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {};
   limit_info.BasicLimitInformation.LimitFlags = limit_flags;
   return 0 != SetInformationJobObject(
       job_object,
@@ -274,76 +374,12 @@
   return GetAppOutput(cl.GetCommandLineString(), output);
 }
 
+bool GetAppOutputAndError(const CommandLine& cl, std::string* output) {
+  return GetAppOutputInternal(cl.GetCommandLineString(), true, 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;
+  return GetAppOutputInternal(cl, false, output);
 }
 
 void RaiseProcessToHighPriority() {
diff --git a/base/process/memory_mac.mm b/base/process/memory_mac.mm
index 4d719f8..17249a2 100644
--- a/base/process/memory_mac.mm
+++ b/base/process/memory_mac.mm
@@ -246,7 +246,7 @@
 // === Core Foundation CFAllocators ===
 
 bool CanGetContextForCFAllocator() {
-  return !base::mac::IsOSLaterThanYosemite_DontCallThis();
+  return !base::mac::IsOSLaterThanElCapitan_DontCallThis();
 }
 
 CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) {
@@ -258,7 +258,8 @@
   } else if (base::mac::IsOSLion() ||
              base::mac::IsOSMountainLion() ||
              base::mac::IsOSMavericks() ||
-             base::mac::IsOSYosemite()) {
+             base::mac::IsOSYosemite() ||
+             base::mac::IsOSElCapitan()) {
     ChromeCFAllocatorLions* our_allocator =
         const_cast<ChromeCFAllocatorLions*>(
             reinterpret_cast<const ChromeCFAllocatorLions*>(allocator));
diff --git a/base/process/memory_stubs.cc b/base/process/memory_stubs.cc
index b06c7d5..a99e94d 100644
--- a/base/process/memory_stubs.cc
+++ b/base/process/memory_stubs.cc
@@ -4,6 +4,8 @@
 
 #include "base/process/memory.h"
 
+#include <stdlib.h>
+
 namespace base {
 
 void EnableTerminationOnOutOfMemory() {
@@ -16,4 +18,22 @@
   return false;
 }
 
+// UncheckedMalloc and Calloc exist so that platforms making use of
+// EnableTerminationOnOutOfMemory have a way to allocate memory without
+// crashing. This _stubs.cc file is for platforms that do not support
+// EnableTerminationOnOutOfMemory (note the empty implementation above). As
+// such, these two Unchecked.alloc functions need only trivially pass-through to
+// their respective stdlib function since those functions will return null on a
+// failure to allocate.
+
+bool UncheckedMalloc(size_t size, void** result) {
+  *result = malloc(size);
+  return *result != nullptr;
+}
+
+bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
+  *result = calloc(num_items, size);
+  return *result != nullptr;
+}
+
 }  // namespace base
diff --git a/base/process/memory_unittest.cc b/base/process/memory_unittest.cc
index 0276b49..98f049a 100644
--- a/base/process/memory_unittest.cc
+++ b/base/process/memory_unittest.cc
@@ -30,6 +30,16 @@
 #endif
 
 #if defined(OS_WIN)
+
+#if defined(_MSC_VER)
+// ssize_t needed for OutOfMemoryTest.
+#if defined(_WIN64)
+typedef __int64 ssize_t;
+#else
+typedef long ssize_t;
+#endif
+#endif
+
 // HeapQueryInformation function pointer.
 typedef BOOL (WINAPI* HeapQueryFn)  \
     (HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
@@ -130,8 +140,9 @@
 // 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) && \
+// Windows only supports these tests with the allocator shim in place.
+#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) &&   \
+    !(defined(OS_WIN) && !defined(ALLOCATOR_SHIM)) && \
     !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
 
 #if defined(USE_TCMALLOC)
@@ -151,6 +162,9 @@
     // 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),
+    // A test size that is > 2Gb and will cause the allocators to reject
+    // the allocation due to security restrictions. See crbug.com/169327.
+    insecure_test_size_(std::numeric_limits<int>::max()),
     signed_test_size_(std::numeric_limits<ssize_t>::max()) {
   }
 
@@ -163,6 +177,7 @@
  protected:
   void* value_;
   size_t test_size_;
+  size_t insecure_test_size_;
   ssize_t signed_test_size_;
 };
 
@@ -213,6 +228,47 @@
     }, kOomRegex);
 }
 
+// OS X has no 2Gb allocation limit.
+// See https://crbug.com/169327.
+#if !defined(OS_MACOSX)
+TEST_F(OutOfMemoryDeathTest, SecurityNew) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = operator new(insecure_test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, SecurityNewArray) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = new char[insecure_test_size_];
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, SecurityMalloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc(insecure_test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, SecurityRealloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = realloc(NULL, insecure_test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, SecurityCalloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = calloc(1024, insecure_test_size_ / 1024L);
+    }, kOomRegex);
+}
+#endif  // !defined(OS_MACOSX)
+
+#if defined(OS_LINUX)
+
 TEST_F(OutOfMemoryDeathTest, Valloc) {
   ASSERT_DEATH({
       SetUpInDeathAssert();
@@ -220,7 +276,12 @@
     }, kOomRegex);
 }
 
-#if defined(OS_LINUX)
+TEST_F(OutOfMemoryDeathTest, SecurityValloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = valloc(insecure_test_size_);
+    }, kOomRegex);
+}
 
 #if PVALLOC_AVAILABLE == 1
 TEST_F(OutOfMemoryDeathTest, Pvalloc) {
@@ -229,6 +290,13 @@
       value_ = pvalloc(test_size_);
     }, kOomRegex);
 }
+
+TEST_F(OutOfMemoryDeathTest, SecurityPvalloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = pvalloc(insecure_test_size_);
+    }, kOomRegex);
+}
 #endif  // PVALLOC_AVAILABLE == 1
 
 TEST_F(OutOfMemoryDeathTest, Memalign) {
@@ -415,5 +483,5 @@
   EXPECT_TRUE(value_ == NULL);
 }
 #endif  // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-#endif  // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) &&
-        // !defined(ADDRESS_SANITIZER)
+#endif  // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !(defined(OS_WIN) &&
+        // !defined(ALLOCATOR_SHIM)) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
diff --git a/base/process/memory_win.cc b/base/process/memory_win.cc
index fc57b48..b949b5d 100644
--- a/base/process/memory_win.cc
+++ b/base/process/memory_win.cc
@@ -10,6 +10,21 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 
+// malloc_unchecked is required to implement UncheckedMalloc properly.
+// It's provided by allocator_shim_win.cc but since that's not always present,
+// we provide a default that falls back to regular malloc.
+typedef void* (*MallocFn)(size_t);
+extern "C" void* (*const malloc_unchecked)(size_t);
+extern "C" void* (*const malloc_default)(size_t) = &malloc;
+
+#if defined(_M_IX86)
+#pragma comment(linker, "/alternatename:_malloc_unchecked=_malloc_default")
+#elif defined(_M_X64) || defined(_M_ARM)
+#pragma comment(linker, "/alternatename:malloc_unchecked=malloc_default")
+#else
+#error Unsupported platform
+#endif
+
 namespace base {
 
 namespace {
@@ -17,10 +32,12 @@
 #pragma warning(push)
 #pragma warning(disable: 4702)
 
-int OnNoMemory(size_t) {
+int OnNoMemory(size_t size) {
   // Kill the process. This is important for security since most of code
   // does not check the result of memory allocation.
-  __debugbreak();
+  LOG(FATAL) << "Out of memory, size = " << size;
+
+  // Safety check, make sure process exits here.
   _exit(1);
   return 0;
 }
@@ -88,14 +105,9 @@
   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.
+// Implemented using a weak symbol.
 bool UncheckedMalloc(size_t size, void** result) {
-  *result = malloc(size);
+  *result = malloc_unchecked(size);
   return *result != NULL;
 }
 
diff --git a/base/process/port_provider_mac.cc b/base/process/port_provider_mac.cc
new file mode 100644
index 0000000..ac13949
--- /dev/null
+++ b/base/process/port_provider_mac.cc
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/port_provider_mac.h"
+
+namespace base {
+
+PortProvider::PortProvider() : lock_(), observer_list_() {}
+PortProvider::~PortProvider() {}
+
+void PortProvider::AddObserver(Observer* observer) {
+  base::AutoLock l(lock_);
+  observer_list_.AddObserver(observer);
+}
+
+void PortProvider::RemoveObserver(Observer* observer) {
+  base::AutoLock l(lock_);
+  observer_list_.RemoveObserver(observer);
+}
+
+void PortProvider::NotifyObservers(ProcessHandle process) {
+  base::AutoLock l(lock_);
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnReceivedTaskPort(process));
+}
+
+}  // namespace base
diff --git a/base/process/port_provider_mac.h b/base/process/port_provider_mac.h
new file mode 100644
index 0000000..2f40297
--- /dev/null
+++ b/base/process/port_provider_mac.h
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_PORT_PROVIDER_MAC_H_
+#define BASE_PROCESS_PORT_PROVIDER_MAC_H_
+
+#include <mach/mach.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "base/process/process_handle.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// Abstract base class that provides a mapping from ProcessHandle (pid_t) to the
+// Mach task port. This replicates task_for_pid(), which requires root
+// privileges.
+class BASE_EXPORT PortProvider {
+ public:
+  PortProvider();
+  virtual ~PortProvider();
+
+  class Observer {
+   public:
+    virtual ~Observer() {};
+    // Called by the PortProvider to notify observers that the task port was
+    // received for a given process.
+    // No guarantees are made about the thread on which this notification will
+    // be sent.
+    // Observers must not call AddObserver() or RemoveObserver() in this
+    // callback, as doing so will deadlock.
+    virtual void OnReceivedTaskPort(ProcessHandle process) = 0;
+  };
+
+  // Returns the mach task port for |process| if possible, or else
+  // |MACH_PORT_NULL|.
+  virtual mach_port_t TaskForPid(ProcessHandle process) const = 0;
+
+  // Observer interface.
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+ protected:
+  // Called by subclasses to send a notification to observers.
+  void NotifyObservers(ProcessHandle process);
+
+ private:
+  // ObserverList is not thread-safe, so |lock_| ensures consistency of
+  // |observer_list_|.
+  base::Lock lock_;
+  base::ObserverList<Observer> observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(PortProvider);
+};
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PORT_PROVIDER_MAC_H_
diff --git a/base/process/process.h b/base/process/process.h
index 808baeb..36f8574 100644
--- a/base/process/process.h
+++ b/base/process/process.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -32,19 +32,17 @@
 // 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)
+  MOVE_ONLY_TYPE_FOR_CPP_03(Process)
 
  public:
   explicit Process(ProcessHandle handle = kNullProcessHandle);
 
-  // Move constructor for C++03 move emulation of this type.
-  Process(RValue other);
+  Process(Process&& other);
 
   // The destructor does not terminate the process.
   ~Process();
 
-  // Move operator= for C++03 move emulation of this type.
-  Process& operator=(RValue other);
+  Process& operator=(Process&& other);
 
   // Returns an object for the current process.
   static Process Current();
@@ -102,9 +100,13 @@
   // On POSIX, if the process has been signaled then |exit_code| is set to -1.
   // On Linux this must be a child process, however on Mac and Windows it can be
   // any process.
+  // NOTE: |exit_code| is optional, nullptr can be passed if the exit code is
+  // not required.
   bool WaitForExit(int* exit_code);
 
   // Same as WaitForExit() but only waits for up to |timeout|.
+  // NOTE: |exit_code| is optional, nullptr can be passed if the exit code
+  // is not required.
   bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code);
 
   // A process is backgrounded when it's priority is lower than normal.
@@ -130,6 +132,14 @@
 #endif
 };
 
+#if defined(OS_CHROMEOS)
+// Exposed for testing.
+// Given the contents of the /proc/<pid>/cgroup file, determine whether the
+// process is backgrounded or not.
+BASE_EXPORT bool IsProcessBackgroundedCGroup(
+    const StringPiece& cgroup_contents);
+#endif  // defined(OS_CHROMEOS)
+
 }  // namespace base
 
 #endif  // BASE_PROCESS_PROCESS_H_
diff --git a/base/process/process_handle.cc b/base/process/process_handle.cc
new file mode 100644
index 0000000..1f22b93
--- /dev/null
+++ b/base/process/process_handle.cc
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace {
+bool g_have_unique_id = false;
+uint32_t g_unique_id;
+
+// The process which set |g_unique_id|.
+ProcessId g_procid;
+
+// Mangle IDs so that they are not accidentally used as PIDs, e.g. as an
+// argument to kill or waitpid.
+uint32_t MangleProcessId(ProcessId process_id) {
+  // Add a large power of 10 so that the pid is still the pid is still readable
+  // inside the mangled id.
+  return static_cast<uint32_t>(process_id) + 1000000000U;
+}
+
+}  // namespace
+
+uint32_t GetUniqueIdForProcess() {
+  if (!g_have_unique_id) {
+    return MangleProcessId(GetCurrentProcId());
+  }
+
+  // Make sure we are the same process that set |g_procid|. This check may have
+  // false negatives (if a process ID was reused) but should have no false
+  // positives.
+  DCHECK_EQ(GetCurrentProcId(), g_procid);
+  return g_unique_id;
+}
+
+#if defined(OS_LINUX)
+
+void InitUniqueIdForProcessInPidNamespace(ProcessId pid_outside_of_namespace) {
+  g_unique_id = MangleProcessId(pid_outside_of_namespace);
+  g_procid = GetCurrentProcId();
+  g_have_unique_id = true;
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/process/process_handle.h b/base/process/process_handle.h
index 77f2c58..0e667c8 100644
--- a/base/process/process_handle.h
+++ b/base/process/process_handle.h
@@ -5,12 +5,13 @@
 #ifndef BASE_PROCESS_PROCESS_HANDLE_H_
 #define BASE_PROCESS_PROCESS_HANDLE_H_
 
+#include <stdint.h>
+#include <sys/types.h>
+
 #include "base/base_export.h"
-#include "base/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
@@ -35,15 +36,36 @@
 #endif  // defined(OS_WIN)
 
 // Returns the id of the current process.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes (use GetUniqueIdForProcess if uniqueness is required).
 BASE_EXPORT ProcessId GetCurrentProcId();
 
+// Returns a unique ID for the current process. The ID will be unique across all
+// currently running processes within the chrome session, but IDs of terminated
+// processes may be reused. This returns an opaque value that is different from
+// a process's PID.
+BASE_EXPORT uint32_t GetUniqueIdForProcess();
+
+#if defined(OS_LINUX)
+// When a process is started in a different PID namespace from the browser
+// process, this function must be called with the process's PID in the browser's
+// PID namespace in order to initialize its unique ID. Not thread safe.
+// WARNING: To avoid inconsistent results from GetUniqueIdForProcess, this
+// should only be called very early after process startup - ideally as soon
+// after process creation as possible.
+BASE_EXPORT void InitUniqueIdForProcessInPidNamespace(
+    ProcessId pid_outside_of_namespace);
+#endif
+
 // Returns the ProcessHandle of the current process.
 BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
 
-// Returns the 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.
+// Returns the process ID for the specified process. This is functionally the
+// same as Windows' GetProcessId(), but works on versions of Windows before Win
+// XP SP1 as well.
 // DEPRECATED. New code should be using Process::Pid() instead.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes.
 BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
 
 #if defined(OS_POSIX)
diff --git a/base/process/process_info_linux.cc b/base/process/process_info_linux.cc
index 9ec2313..88ae5a1 100644
--- a/base/process/process_info_linux.cc
+++ b/base/process/process_info_linux.cc
@@ -12,7 +12,7 @@
 
 namespace base {
 
-//static
+// static
 const Time CurrentProcessInfo::CreationTime() {
   ProcessHandle pid = GetCurrentProcessHandle();
   int64 start_ticks =
diff --git a/base/process/process_info_mac.cc b/base/process/process_info_mac.cc
index b7cfdce..7680d37 100644
--- a/base/process/process_info_mac.cc
+++ b/base/process/process_info_mac.cc
@@ -14,7 +14,7 @@
 
 namespace base {
 
-//static
+// static
 const Time CurrentProcessInfo::CreationTime() {
   int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
   size_t len = 0;
diff --git a/base/process/process_iterator_freebsd.cc b/base/process/process_iterator_freebsd.cc
index 5b1e2ab..1d60393 100644
--- a/base/process/process_iterator_freebsd.cc
+++ b/base/process/process_iterator_freebsd.cc
@@ -4,11 +4,13 @@
 
 #include "base/process/process_iterator.h"
 
+#include <errno.h>
 #include <sys/types.h>
 #include <sys/sysctl.h>
 #include <unistd.h>
 
 #include "base/logging.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 
 namespace base {
@@ -88,7 +90,8 @@
 
     std::string delimiters;
     delimiters.push_back('\0');
-    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+    entry_.cmd_line_args_ = SplitString(data, delimiters,
+                                        KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
 
     size_t exec_name_end = data.find('\0');
     if (exec_name_end == std::string::npos) {
diff --git a/base/process/process_iterator_linux.cc b/base/process/process_iterator_linux.cc
index 3319552..a9d044c 100644
--- a/base/process/process_iterator_linux.cc
+++ b/base/process/process_iterator_linux.cc
@@ -7,6 +7,7 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/process/internal_linux.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
 
@@ -48,7 +49,8 @@
     return false;
   std::string delimiters;
   delimiters.push_back('\0');
-  Tokenize(cmd_line, delimiters, proc_cmd_line_args);
+  *proc_cmd_line_args = SplitString(cmd_line, delimiters, KEEP_WHITESPACE,
+                                    SPLIT_WANT_NONEMPTY);
   return true;
 }
 
diff --git a/base/process/process_iterator_mac.cc b/base/process/process_iterator_mac.cc
index e35c2ae..d9136f4 100644
--- a/base/process/process_iterator_mac.cc
+++ b/base/process/process_iterator_mac.cc
@@ -10,6 +10,7 @@
 #include <unistd.h>
 
 #include "base/logging.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 
 namespace base {
@@ -21,7 +22,8 @@
   // 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() };
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID,
+                static_cast<int>(geteuid()) };
 
   // Since more processes could start between when we get the size and when
   // we get the list, we do a loop to keep trying until we get it.
@@ -99,7 +101,8 @@
     // |entry_.cmd_line_args_|.
     std::string delimiters;
     delimiters.push_back('\0');
-    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+    entry_.cmd_line_args_ = SplitString(data, delimiters,
+                                        KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
 
     // |data| starts with the full executable path followed by a null character.
     // We search for the first instance of '\0' and extract everything before it
diff --git a/base/process/process_iterator_openbsd.cc b/base/process/process_iterator_openbsd.cc
index 7c44eb1..f864f58 100644
--- a/base/process/process_iterator_openbsd.cc
+++ b/base/process/process_iterator_openbsd.cc
@@ -8,6 +8,7 @@
 #include <sys/sysctl.h>
 
 #include "base/logging.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 
 namespace base {
@@ -92,7 +93,8 @@
     // |entry_.cmd_line_args_|.
     std::string delimiters;
     delimiters.push_back('\0');
-    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+    entry_.cmd_line_args_ = SplitString(data, delimiters, KEEP_WHITESPACE,
+                                        SPLIT_WANT_NONEMPTY);
 
     // |data| starts with the full executable path followed by a null character.
     // We search for the first instance of '\0' and extract everything before it
diff --git a/base/process/process_linux.cc b/base/process/process_linux.cc
index 88a310e..78000db 100644
--- a/base/process/process_linux.cc
+++ b/base/process/process_linux.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
@@ -59,10 +60,10 @@
   }
 };
 
-base::LazyInstance<CGroups> cgroups = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<CGroups> g_cgroups = LAZY_INSTANCE_INITIALIZER;
 #else
 const int kBackgroundPriority = 5;
-#endif
+#endif  // defined(OS_CHROMEOS)
 
 struct CheckForNicePermission {
   CheckForNicePermission() : can_reraise_priority(false) {
@@ -83,9 +84,9 @@
 // static
 bool Process::CanBackgroundProcesses() {
 #if defined(OS_CHROMEOS)
-  if (cgroups.Get().enabled)
+  if (g_cgroups.Get().enabled)
     return true;
-#endif
+#endif  // defined(OS_CHROMEOS)
 
   static LazyInstance<CheckForNicePermission> check_for_nice_permission =
       LAZY_INSTANCE_INITIALIZER;
@@ -96,21 +97,18 @@
   DCHECK(IsValid());
 
 #if defined(OS_CHROMEOS)
-  if (cgroups.Get().enabled) {
+  if (g_cgroups.Get().enabled) {
+    // Used to allow reading the process priority from proc on thread launch.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     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;
+            base::FilePath(StringPrintf(kProcPath, process_)), &proc)) {
+      return IsProcessBackgroundedCGroup(proc);
     }
+    return false;
   }
-#endif
+#endif  // defined(OS_CHROMEOS)
+
   return GetPriority() == kBackgroundPriority;
 }
 
@@ -118,14 +116,14 @@
   DCHECK(IsValid());
 
 #if defined(OS_CHROMEOS)
-  if (cgroups.Get().enabled) {
-    std::string pid = StringPrintf("%d", process_);
+  if (g_cgroups.Get().enabled) {
+    std::string pid = IntToString(process_);
     const base::FilePath file =
         background ?
-            cgroups.Get().background_file : cgroups.Get().foreground_file;
+            g_cgroups.Get().background_file : g_cgroups.Get().foreground_file;
     return base::WriteFile(file, pid.c_str(), pid.size()) > 0;
   }
-#endif // OS_CHROMEOS
+#endif  // defined(OS_CHROMEOS)
 
   if (!CanBackgroundProcesses())
     return false;
@@ -136,4 +134,27 @@
   return result == 0;
 }
 
+#if defined(OS_CHROMEOS)
+bool IsProcessBackgroundedCGroup(const StringPiece& cgroup_contents) {
+  // The process can be part of multiple control groups, and for each cgroup
+  // hierarchy there's an entry in the file. We look for a control group
+  // named "/chrome_renderers/background" to determine if the process is
+  // backgrounded. crbug.com/548818.
+  std::vector<StringPiece> lines = SplitStringPiece(
+      cgroup_contents, "\n", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  for (const auto& line : lines) {
+    std::vector<StringPiece> fields =
+        SplitStringPiece(line, ":", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+    if (fields.size() != 3U) {
+      NOTREACHED();
+      continue;
+    }
+    if (fields[2] == kBackground)
+      return true;
+  }
+
+  return false;
+}
+#endif  // defined(OS_CHROMEOS)
+
 }  // namespace base
diff --git a/base/process/process_metrics.cc b/base/process/process_metrics.cc
index e486339..f4a3ea1 100644
--- a/base/process/process_metrics.cc
+++ b/base/process/process_metrics.cc
@@ -4,6 +4,8 @@
 
 #include "base/process/process_metrics.h"
 
+#include <utility>
+
 #include "base/logging.h"
 #include "base/values.h"
 
@@ -40,7 +42,15 @@
   res->Set("swapinfo", swap_info_.ToValue());
 #endif
 
-  return res.Pass();
+  return std::move(res);
+}
+
+ProcessMetrics* ProcessMetrics::CreateCurrentProcessMetrics() {
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  return CreateProcessMetrics(base::GetCurrentProcessHandle());
+#else
+  return CreateProcessMetrics(base::GetCurrentProcessHandle(), nullptr);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
 }
 
 double ProcessMetrics::GetPlatformIndependentCPUUsage() {
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
index 5916b94..40c9644 100644
--- a/base/process/process_metrics.h
+++ b/base/process/process_metrics.h
@@ -19,6 +19,7 @@
 
 #if defined(OS_MACOSX)
 #include <mach/mach.h>
+#include "base/process/port_provider_mac.h"
 #endif
 
 namespace base {
@@ -89,8 +90,9 @@
 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
+// IO counters). Use CreateCurrentProcessMetrics() to get an instance for the
+// current process, or CreateProcessMetrics() to get an instance for an
+// arbitrary process. Then, access the information with the different get
 // methods.
 class BASE_EXPORT ProcessMetrics {
  public:
@@ -101,16 +103,6 @@
 #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
@@ -119,6 +111,11 @@
                                               PortProvider* port_provider);
 #endif  // !defined(OS_MACOSX) || defined(OS_IOS)
 
+  // Creates a ProcessMetrics for the current process. This a cross-platform
+  // convenience wrapper for CreateProcessMetrics().
+  // The caller owns the returned object.
+  static ProcessMetrics* CreateCurrentProcessMetrics();
+
   // Returns the current space allocated for the pagefile, in bytes (these pages
   // may or may not be in memory).  On Linux, this returns the total virtual
   // memory size.
@@ -140,7 +137,8 @@
   // 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.
+  // usage in bytes, as per definition of WorkingSetBytes. Note that this
+  // function is somewhat expensive on Windows (a few ms per process).
   bool GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const;
 
 #if defined(OS_MACOSX)
@@ -241,6 +239,65 @@
 BASE_EXPORT void SetFdLimit(unsigned int max_descriptors);
 #endif  // defined(OS_POSIX)
 
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
+    defined(OS_ANDROID)
+// Data about system-wide memory consumption. Values are in KB. Available on
+// Windows, Mac, Linux, Android and Chrome OS.
+//
+// Total/free memory are available on all platforms that implement
+// GetSystemMemoryInfo(). Total/free swap memory are available on all platforms
+// except on Mac. Buffers/cached/active_anon/inactive_anon/active_file/
+// inactive_file/dirty/pswpin/pswpout/pgmajfault are available on
+// Linux/Android/Chrome OS. Shmem/slab/gem_objects/gem_size are Chrome OS only.
+struct BASE_EXPORT SystemMemoryInfoKB {
+  SystemMemoryInfoKB();
+
+  // Serializes the platform specific fields to value.
+  scoped_ptr<Value> ToValue() const;
+
+  int total;
+  int free;
+
+#if !defined(OS_MACOSX)
+  int swap_total;
+  int swap_free;
+#endif
+
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+  int buffers;
+  int cached;
+  int active_anon;
+  int inactive_anon;
+  int active_file;
+  int inactive_file;
+  int dirty;
+
+  // vmstats data.
+  int pswpin;
+  int pswpout;
+  int pgmajfault;
+#endif  // defined(OS_ANDROID) || defined(OS_LINUX)
+
+#if defined(OS_CHROMEOS)
+  int shmem;
+  int slab;
+  // Gem data will be -1 if not supported.
+  int gem_objects;
+  long long gem_size;
+#endif  // defined(OS_CHROMEOS)
+};
+
+// On Linux/Android/Chrome OS, system-wide memory consumption data is parsed
+// from /proc/meminfo and /proc/vmstat. On Windows/Mac, it is obtained using
+// system API calls.
+//
+// Fills in the provided |meminfo| structure. Returns true on success.
+// Exposed for memory debugging widget.
+BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo);
+
+#endif  // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) ||
+        // defined(OS_ANDROID)
+
 #if defined(OS_LINUX) || defined(OS_ANDROID)
 // Parse the data found in /proc/<pid>/stat and return the sum of the
 // CPU-related ticks.  Returns -1 on parse error.
@@ -256,40 +313,6 @@
 // /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,
@@ -300,12 +323,6 @@
 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();
diff --git a/base/process/process_metrics_ios.cc b/base/process/process_metrics_ios.cc
index 07f2c8d..135ef43 100644
--- a/base/process/process_metrics_ios.cc
+++ b/base/process/process_metrics_ios.cc
@@ -23,6 +23,11 @@
 
 }  // namespace
 
+SystemMemoryInfoKB::SystemMemoryInfoKB() {
+  total = 0;
+  free = 0;
+}
+
 ProcessMetrics::ProcessMetrics(ProcessHandle process) {}
 
 ProcessMetrics::~ProcessMetrics() {}
@@ -82,4 +87,11 @@
   return 0;
 }
 
+// Bytes committed by the system.
+bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
+  // Unimplemented. Must enable unittest for IOS when this gets implemented.
+  NOTIMPLEMENTED();
+  return false;
+}
+
 }  // namespace base
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc
index 2d54c4c..63d6014 100644
--- a/base/process/process_metrics_linux.cc
+++ b/base/process/process_metrics_linux.cc
@@ -10,6 +10,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <utility>
 
 #include "base/files/file_util.h"
 #include "base/logging.h"
@@ -67,8 +68,8 @@
     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);
+      std::vector<StringPiece> split_value_str = SplitStringPiece(
+          value_str, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
       if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
         NOTREACHED();
         return 0;
@@ -228,7 +229,7 @@
   // 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() /
+  double percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() /
       TimeDelta::FromMicroseconds(time_delta).InSecondsF();
 
   last_cpu_time_ = time;
@@ -316,8 +317,9 @@
       return false;
   }
 
-  std::vector<std::string> totmaps_fields;
-  SplitStringAlongWhitespace(totmaps_data, &totmaps_fields);
+  std::vector<std::string> totmaps_fields = SplitString(
+      totmaps_data, base::kWhitespaceASCII, base::KEEP_WHITESPACE,
+      base::SPLIT_WANT_NONEMPTY);
 
   DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]);
   DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex - 1]);
@@ -368,8 +370,8 @@
       return false;
   }
 
-  std::vector<std::string> statm_vec;
-  SplitString(statm, ' ', &statm_vec);
+  std::vector<StringPiece> statm_vec = SplitStringPiece(
+      statm, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
   if (statm_vec.size() != 7)
     return false;  // Not the format we expect.
 
@@ -543,7 +545,7 @@
   res->SetInteger("gem_size", gem_size);
 #endif
 
-  return res.Pass();
+  return std::move(res);
 }
 
 // exposed for testing
@@ -563,17 +565,15 @@
   // 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);
+  for (const StringPiece& line : SplitStringPiece(
+           meminfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
+    std::vector<StringPiece> tokens = SplitStringPiece(
+        line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
     // HugePages_* only has a number and no suffix so we can't rely on
     // there being exactly 3 tokens.
     if (tokens.size() <= 1) {
       DLOG(WARNING) << "meminfo: tokens: " << tokens.size()
-                    << " malformed line: " << *it;
+                    << " malformed line: " << line.as_string();
       continue;
     }
 
@@ -630,12 +630,10 @@
   // 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);
+  for (const StringPiece& line : SplitStringPiece(
+           vmstat_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
+    std::vector<StringPiece> tokens = SplitStringPiece(
+        line, " ", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
     if (tokens.size() != 2)
       continue;
 
@@ -750,7 +748,7 @@
   res->SetDouble("io_time", static_cast<double>(io_time));
   res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time));
 
-  return res.Pass();
+  return std::move(res);
 }
 
 bool IsValidDiskName(const std::string& candidate) {
@@ -792,9 +790,9 @@
     return false;
   }
 
-  std::vector<std::string> diskinfo_lines;
-  size_t line_count = Tokenize(diskinfo_data, "\n", &diskinfo_lines);
-  if (line_count == 0) {
+  std::vector<StringPiece> diskinfo_lines = SplitStringPiece(
+      diskinfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  if (diskinfo_lines.size() == 0) {
     DLOG(WARNING) << "No lines found";
     return false;
   }
@@ -823,12 +821,12 @@
   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);
+  for (const StringPiece& line : diskinfo_lines) {
+    std::vector<StringPiece> disk_fields = SplitStringPiece(
+        line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
 
     // Fields may have overflowed and reset to zero.
-    if (IsValidDiskName(disk_fields[kDiskDriveName])) {
+    if (IsValidDiskName(disk_fields[kDiskDriveName].as_string())) {
       StringToUint64(disk_fields[kDiskReads], &reads);
       StringToUint64(disk_fields[kDiskReadsMerged], &reads_merged);
       StringToUint64(disk_fields[kDiskSectorsRead], &sectors_read);
@@ -875,7 +873,7 @@
   else
     res->SetDouble("compression_ratio", 0);
 
-  return res.Pass();
+  return std::move(res);
 }
 
 void GetSwapInfo(SwapInfo* swap_info) {
diff --git a/base/process/process_metrics_mac.cc b/base/process/process_metrics_mac.cc
index f84b435..82acb06 100644
--- a/base/process/process_metrics_mac.cc
+++ b/base/process/process_metrics_mac.cc
@@ -77,6 +77,11 @@
 
 }  // namespace
 
+SystemMemoryInfoKB::SystemMemoryInfoKB() {
+  total = 0;
+  free = 0;
+}
+
 // 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
@@ -86,7 +91,7 @@
 // static
 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(
     ProcessHandle process,
-    ProcessMetrics::PortProvider* port_provider) {
+    PortProvider* port_provider) {
   return new ProcessMetrics(process, port_provider);
 }
 
@@ -325,7 +330,7 @@
 }
 
 ProcessMetrics::ProcessMetrics(ProcessHandle process,
-                               ProcessMetrics::PortProvider* port_provider)
+                               PortProvider* port_provider)
     : process_(process),
       last_system_time_(0),
       last_absolute_idle_wakeups_(0),
@@ -347,7 +352,7 @@
   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,
+  kern_return_t kr = host_statistics(host.get(), HOST_VM_INFO,
                                      reinterpret_cast<host_info_t>(&data),
                                      &count);
   if (kr != KERN_SUCCESS) {
@@ -358,4 +363,32 @@
   return (data.active_count * PAGE_SIZE) / 1024;
 }
 
+// On Mac, We only get total memory and free memory from the system.
+bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
+  struct host_basic_info hostinfo;
+  mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  int result = host_info(host.get(), HOST_BASIC_INFO,
+                         reinterpret_cast<host_info_t>(&hostinfo), &count);
+  if (result != KERN_SUCCESS)
+    return false;
+
+  DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
+  meminfo->total = static_cast<int>(hostinfo.max_mem / 1024);
+
+  vm_statistics_data_t vm_info;
+  count = HOST_VM_INFO_COUNT;
+
+  if (host_statistics(host.get(), HOST_VM_INFO,
+                      reinterpret_cast<host_info_t>(&vm_info),
+                      &count) != KERN_SUCCESS) {
+    return false;
+  }
+
+  meminfo->free = static_cast<int>(
+      (vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE / 1024);
+
+  return true;
+}
+
 }  // namespace base
diff --git a/base/process/process_metrics_nacl.cc b/base/process/process_metrics_nacl.cc
new file mode 100644
index 0000000..baf3294
--- /dev/null
+++ b/base/process/process_metrics_nacl.cc
@@ -0,0 +1,15 @@
+// Copyright 2015 The Chromium Authors. All 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 <unistd.h>
+
+namespace base {
+
+size_t GetPageSize() {
+  return getpagesize();
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_posix.cc b/base/process/process_metrics_posix.cc
index 42b3f2d..3f1bcb6 100644
--- a/base/process/process_metrics_posix.cc
+++ b/base/process/process_metrics_posix.cc
@@ -6,6 +6,7 @@
 
 #include <sys/resource.h>
 #include <sys/time.h>
+#include <unistd.h>
 
 #include "base/logging.h"
 
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc
index 76767b0..31479ce 100644
--- a/base/process/process_metrics_unittest.cc
+++ b/base/process/process_metrics_unittest.cc
@@ -270,7 +270,8 @@
 }
 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
+    defined(OS_LINUX) || defined(OS_ANDROID)
 TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
   base::SystemMemoryInfoKB info;
   EXPECT_TRUE(base::GetSystemMemoryInfo(&info));
@@ -278,21 +279,25 @@
   // Ensure each field received a value.
   EXPECT_GT(info.total, 0);
   EXPECT_GT(info.free, 0);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
   EXPECT_GT(info.buffers, 0);
   EXPECT_GT(info.cached, 0);
   EXPECT_GT(info.active_anon, 0);
   EXPECT_GT(info.inactive_anon, 0);
   EXPECT_GT(info.active_file, 0);
   EXPECT_GT(info.inactive_file, 0);
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
   // All the values should be less than the total amount of memory.
   EXPECT_LT(info.free, info.total);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
   EXPECT_LT(info.buffers, info.total);
   EXPECT_LT(info.cached, info.total);
   EXPECT_LT(info.active_anon, info.total);
   EXPECT_LT(info.inactive_anon, info.total);
   EXPECT_LT(info.active_file, info.total);
   EXPECT_LT(info.inactive_file, info.total);
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
   // Chrome OS exposes shmem.
@@ -302,7 +307,8 @@
   // and gem_size cannot be tested here.
 #endif
 }
-#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+#endif  // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) ||
+        // defined(OS_LINUX) || defined(OS_ANDROID)
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
 TEST(ProcessMetricsTest, ParseProcStatCPU) {
diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc
index 1dd97e6..63b7d96 100644
--- a/base/process/process_metrics_win.cc
+++ b/base/process/process_metrics_win.cc
@@ -6,15 +6,34 @@
 
 #include <windows.h>
 #include <psapi.h>
+#include <winternl.h>
+
+#include <algorithm>
 
 #include "base/logging.h"
 #include "base/sys_info.h"
 
 namespace base {
+namespace {
 
 // System pagesize. This value remains constant on x86/64 architectures.
 const int PAGESIZE_KB = 4;
 
+typedef NTSTATUS(WINAPI* NTQUERYSYSTEMINFORMATION)(
+    SYSTEM_INFORMATION_CLASS SystemInformationClass,
+    PVOID SystemInformation,
+    ULONG SystemInformationLength,
+    PULONG ReturnLength);
+
+}  // namespace
+
+SystemMemoryInfoKB::SystemMemoryInfoKB() {
+  total = 0;
+  free = 0;
+  swap_total = 0;
+  swap_free = 0;
+}
+
 ProcessMetrics::~ProcessMetrics() { }
 
 // static
@@ -225,14 +244,11 @@
   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;
+  return static_cast<double>(system_time_delta * 100.0) / time_delta;
 }
 
 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
@@ -263,7 +279,7 @@
           GetProcAddress(psapi_dll, "GetPerformanceInfo"));
 
     if (!GetPerformanceInfo_func) {
-      // The function could be loaded!
+      // The function could not be loaded!
       memset(pPerformanceInformation, 0, cb);
       return FALSE;
     }
@@ -288,4 +304,24 @@
   return PAGESIZE_KB * 1024;
 }
 
+// This function uses the following mapping between MEMORYSTATUSEX and
+// SystemMemoryInfoKB:
+//   ullTotalPhys ==> total
+//   ullAvailPhys ==> free
+//   ullTotalPageFile ==> swap_total
+//   ullAvailPageFile ==> swap_free
+bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
+  MEMORYSTATUSEX mem_status;
+  mem_status.dwLength = sizeof(mem_status);
+  if (!::GlobalMemoryStatusEx(&mem_status))
+    return false;
+
+  meminfo->total = mem_status.ullTotalPhys / 1024;
+  meminfo->free = mem_status.ullAvailPhys / 1024;
+  meminfo->swap_total = mem_status.ullTotalPageFile / 1024;
+  meminfo->swap_free = mem_status.ullAvailPageFile / 1024;
+
+  return true;
+}
+
 }  // namespace base
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc
index a7d16f8..7b2eed7 100644
--- a/base/process/process_posix.cc
+++ b/base/process/process_posix.cc
@@ -1,9 +1,10 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/process/process.h"
 
+#include <errno.h>
 #include <sys/resource.h>
 #include <sys/wait.h>
 
@@ -193,11 +194,13 @@
   if (!WaitpidWithTimeout(handle, &status, timeout))
     return false;
   if (WIFSIGNALED(status)) {
-    *exit_code = -1;
+    if (exit_code)
+      *exit_code = -1;
     return true;
   }
   if (WIFEXITED(status)) {
-    *exit_code = WEXITSTATUS(status);
+    if (exit_code)
+      *exit_code = WEXITSTATUS(status);
     return true;
   }
   return false;
@@ -214,16 +217,14 @@
 Process::~Process() {
 }
 
-Process::Process(RValue other)
-    : process_(other.object->process_) {
-  other.object->Close();
+Process::Process(Process&& other) : process_(other.process_) {
+  other.Close();
 }
 
-Process& Process::operator=(RValue other) {
-  if (this != other.object) {
-    process_ = other.object->process_;
-    other.object->Close();
-  }
+Process& Process::operator=(Process&& other) {
+  DCHECK_NE(this, &other);
+  process_ = other.process_;
+  other.Close();
   return *this;
 }
 
@@ -293,9 +294,10 @@
 
 #if !defined(OS_NACL_NONSFI)
 bool Process::Terminate(int exit_code, bool wait) const {
-  // result_code isn't supportable.
+  // exit_code isn't supportable.
   DCHECK(IsValid());
-  DCHECK_GT(process_, 1);
+  CHECK_GT(process_, 0);
+
   bool result = kill(process_, SIGTERM) == 0;
   if (result && wait) {
     int tries = 60;
@@ -361,10 +363,10 @@
 }
 
 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());
+  // Not implemented for POSIX systems other than Linux. With POSIX, if we were
+  // to lower the process priority we wouldn't be able to raise it back to its
+  // initial priority.
+  NOTIMPLEMENTED();
   return false;
 }
 #endif  // !defined(OS_LINUX)
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc
index ba8e4e6..6ff5e7f 100644
--- a/base/process/process_unittest.cc
+++ b/base/process/process_unittest.cc
@@ -176,8 +176,10 @@
   EXPECT_TRUE(process.SetProcessBackgrounded(false));
   EXPECT_FALSE(process.IsProcessBackgrounded());
 #else
-  process.SetProcessBackgrounded(true);
-  process.SetProcessBackgrounded(false);
+  if (process.CanBackgroundProcesses()) {
+    process.SetProcessBackgrounded(true);
+    process.SetProcessBackgrounded(false);
+  }
 #endif
   int new_priority = process.GetPriority();
   EXPECT_EQ(old_priority, new_priority);
@@ -201,4 +203,20 @@
   EXPECT_EQ(old_priority, new_priority);
 }
 
+#if defined(OS_CHROMEOS)
+
+// Tests that the function IsProcessBackgroundedCGroup() can parse the contents
+// of the /proc/<pid>/cgroup file successfully.
+TEST_F(ProcessTest, TestIsProcessBackgroundedCGroup) {
+  const char kNotBackgrounded[] = "5:cpuacct,cpu,cpuset:/daemons\n";
+  const char kBackgrounded[] =
+      "2:freezer:/chrome_renderers/to_be_frozen\n"
+      "1:cpu:/chrome_renderers/background\n";
+
+  EXPECT_FALSE(IsProcessBackgroundedCGroup(kNotBackgrounded));
+  EXPECT_TRUE(IsProcessBackgroundedCGroup(kBackgrounded));
+}
+
+#endif  // defined(OS_CHROMEOS)
+
 }  // namespace base
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
index 11d8874..08144f2 100644
--- a/base/process/process_util_unittest.cc
+++ b/base/process/process_util_unittest.cc
@@ -59,21 +59,28 @@
 #include <malloc/malloc.h>
 #include "base/mac/mac_util.h"
 #endif
+#if defined(OS_ANDROID)
+#include "third_party/lss/linux_syscall_support.h"
+#endif
 
 using base::FilePath;
 
 namespace {
 
+const char kSignalFileSlow[] = "SlowChildProcess.die";
+const char kSignalFileKill[] = "KilledChildProcess.die";
+
+#if defined(OS_POSIX)
+const char kSignalFileTerm[] = "TerminatedChildProcess.die";
+
 #if defined(OS_ANDROID)
 const char kShellPath[] = "/system/bin/sh";
 const char kPosixShell[] = "sh";
 #else
 const char kShellPath[] = "/bin/sh";
-const char kPosixShell[] = "bash";
+const char kPosixShell[] = "sh";
 #endif
-
-const char kSignalFileSlow[] = "SlowChildProcess.die";
-const char kSignalFileKill[] = "KilledChildProcess.die";
+#endif  // defined(OS_POSIX)
 
 #if defined(OS_WIN)
 const int kExpectedStillRunningExitCode = 0x102;
@@ -222,7 +229,19 @@
 
 MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
   WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileCrash).c_str());
-#if defined(OS_POSIX)
+#if defined(OS_ANDROID)
+  // Android L+ expose signal and sigaction symbols that override the system
+  // ones. There is a bug in these functions where a request to set the handler
+  // to SIG_DFL is ignored. In that case, an infinite loop is entered as the
+  // signal is repeatedly sent to the crash dump signal handler.
+  // To work around this, directly call the system's sigaction.
+  struct kernel_sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  sys_sigemptyset(&sa.sa_mask);
+  sa.sa_handler_ = SIG_DFL;
+  sa.sa_flags = SA_RESTART;
+  sys_rt_sigaction(SIGSEGV, &sa, NULL, sizeof(kernel_sigset_t));
+#elif 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);
@@ -286,7 +305,16 @@
   return 1;
 }
 
-TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
+#if defined(OS_POSIX)
+MULTIPROCESS_TEST_MAIN(TerminatedChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileTerm).c_str());
+  // Send a SIGTERM to this process.
+  ::kill(getpid(), SIGTERM);
+  return 1;
+}
+#endif
+
+TEST_F(ProcessUtilTest, GetTerminationStatusSigKill) {
   const std::string signal_file =
     ProcessUtilTest::GetSignalFilePath(kSignalFileKill);
   remove(signal_file.c_str());
@@ -302,7 +330,12 @@
   exit_code = 42;
   base::TerminationStatus status =
       WaitForChildTermination(process.Handle(), &exit_code);
+#if defined(OS_CHROMEOS)
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, status);
+#else
   EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
+#endif
+
 #if defined(OS_WIN)
   EXPECT_EQ(kExpectedKilledExitCode, exit_code);
 #elif defined(OS_POSIX)
@@ -314,6 +347,33 @@
   remove(signal_file.c_str());
 }
 
+#if defined(OS_POSIX)
+TEST_F(ProcessUtilTest, GetTerminationStatusSigTerm) {
+  const std::string signal_file =
+    ProcessUtilTest::GetSignalFilePath(kSignalFileTerm);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("TerminatedChildProcess");
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(process.Handle(), &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
+
+  int signaled = WIFSIGNALED(exit_code);
+  EXPECT_NE(0, signaled);
+  int signal = WTERMSIG(exit_code);
+  EXPECT_EQ(SIGTERM, signal);
+  remove(signal_file.c_str());
+}
+#endif
+
 #if defined(OS_WIN)
 // TODO(estade): if possible, port this test.
 TEST_F(ProcessUtilTest, GetAppOutput) {
@@ -980,6 +1040,7 @@
   return kSuccess;
 }
 
+#if defined(CLONE_NEWUSER) && defined(CLONE_NEWPID)
 TEST_F(ProcessUtilTest, CloneFlags) {
   if (RunningOnValgrind() ||
       !base::PathExists(FilePath("/proc/self/ns/user")) ||
@@ -998,6 +1059,7 @@
   EXPECT_TRUE(process.WaitForExit(&exit_code));
   EXPECT_EQ(kSuccess, exit_code);
 }
+#endif
 
 TEST(ForkWithFlagsTest, UpdatesPidCache) {
   // The libc clone function, which allows ForkWithFlags to keep the pid cache
diff --git a/base/process/process_win.cc b/base/process/process_win.cc
index 0d312a3..e7f35b3 100644
--- a/base/process/process_win.cc
+++ b/base/process/process_win.cc
@@ -6,7 +6,6 @@
 
 #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"
@@ -26,21 +25,20 @@
   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&& other)
+    : is_current_process_(other.is_current_process_),
+      process_(other.process_.Take()) {
+  other.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();
-  }
+Process& Process::operator=(Process&& other) {
+  DCHECK_NE(this, &other);
+  process_.Set(other.process_.Take());
+  is_current_process_ = other.is_current_process_;
+  other.Close();
   return *this;
 }
 
@@ -154,7 +152,8 @@
   if (!::GetExitCodeProcess(Handle(), &temp_code))
     return false;
 
-  *exit_code = temp_code;
+  if (exit_code)
+    *exit_code = temp_code;
   return true;
 }
 
@@ -177,21 +176,7 @@
     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;
+    priority = value ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS;
   }
 
   return (::SetPriorityClass(Handle(), priority) != 0);
diff --git a/base/profiler/OWNERS b/base/profiler/OWNERS
new file mode 100644
index 0000000..81ff9fa
--- /dev/null
+++ b/base/profiler/OWNERS
@@ -0,0 +1,5 @@
+# Stack sampling profiler
+per-file native_stack_sampler*=wittman@chromium.org
+per-file stack_sampling_profiler*=wittman@chromium.org
+per-file test_support_library*=wittman@chromium.org
+per-file win32_stack_frame_unwinder*=wittman@chromium.org
diff --git a/base/profiler/native_stack_sampler.cc b/base/profiler/native_stack_sampler.cc
index 8b4731b..968455f 100644
--- a/base/profiler/native_stack_sampler.cc
+++ b/base/profiler/native_stack_sampler.cc
@@ -10,4 +10,8 @@
 
 NativeStackSampler::~NativeStackSampler() {}
 
+NativeStackSamplerTestDelegate::~NativeStackSamplerTestDelegate() {}
+
+NativeStackSamplerTestDelegate::NativeStackSamplerTestDelegate() {}
+
 }  // namespace base
diff --git a/base/profiler/native_stack_sampler.h b/base/profiler/native_stack_sampler.h
index bc170dc..40be5cd 100644
--- a/base/profiler/native_stack_sampler.h
+++ b/base/profiler/native_stack_sampler.h
@@ -5,12 +5,16 @@
 #ifndef BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
 #define BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
 
+#include "base/base_export.h"
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/profiler/stack_sampling_profiler.h"
 #include "base/threading/platform_thread.h"
 
 namespace base {
 
+class NativeStackSamplerTestDelegate;
+
 // NativeStackSampler is an implementation detail of StackSamplingProfiler. It
 // abstracts the native implementation required to record a stack sample for a
 // given thread.
@@ -20,7 +24,9 @@
 
   // 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);
+  static scoped_ptr<NativeStackSampler> Create(
+      PlatformThreadId thread_id,
+      NativeStackSamplerTestDelegate* test_delegate);
 
   // The following functions are all called on the SamplingThread (not the
   // thread being sampled).
@@ -44,6 +50,23 @@
   DISALLOW_COPY_AND_ASSIGN(NativeStackSampler);
 };
 
+// NativeStackSamplerTestDelegate provides seams for test code to execute during
+// stack collection.
+class BASE_EXPORT NativeStackSamplerTestDelegate {
+ public:
+  virtual ~NativeStackSamplerTestDelegate();
+
+  // Called after copying the stack and resuming the target thread, but prior to
+  // walking the stack. Invoked on the SamplingThread.
+  virtual void OnPreStackWalk() = 0;
+
+ protected:
+  NativeStackSamplerTestDelegate();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerTestDelegate);
+};
+
 }  // namespace base
 
 #endif  // BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
diff --git a/base/profiler/stack_sampling_profiler_posix.cc b/base/profiler/native_stack_sampler_posix.cc
similarity index 80%
rename from base/profiler/stack_sampling_profiler_posix.cc
rename to base/profiler/native_stack_sampler_posix.cc
index bce37e1..c67d885 100644
--- a/base/profiler/stack_sampling_profiler_posix.cc
+++ b/base/profiler/native_stack_sampler_posix.cc
@@ -7,7 +7,8 @@
 namespace base {
 
 scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
-    PlatformThreadId thread_id) {
+    PlatformThreadId thread_id,
+    NativeStackSamplerTestDelegate* test_delegate) {
   return scoped_ptr<NativeStackSampler>();
 }
 
diff --git a/base/profiler/native_stack_sampler_win.cc b/base/profiler/native_stack_sampler_win.cc
new file mode 100644
index 0000000..7b41fee
--- /dev/null
+++ b/base/profiler/native_stack_sampler_win.cc
@@ -0,0 +1,504 @@
+// Copyright 2015 The Chromium Authors. 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 <winternl.h>
+
+#include <cstdlib>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/profiler/native_stack_sampler.h"
+#include "base/profiler/win32_stack_frame_unwinder.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 {
+
+// Stack recording functions --------------------------------------------------
+
+namespace {
+
+// The thread environment block internal type.
+struct TEB {
+  NT_TIB Tib;
+  // Rest of struct is ignored.
+};
+
+// Returns the thread environment block pointer for |thread_handle|.
+const TEB* GetThreadEnvironmentBlock(HANDLE thread_handle) {
+  // Define the internal types we need to invoke NtQueryInformationThread.
+  enum THREAD_INFORMATION_CLASS { ThreadBasicInformation };
+
+  struct CLIENT_ID {
+    HANDLE UniqueProcess;
+    HANDLE UniqueThread;
+  };
+
+  struct THREAD_BASIC_INFORMATION {
+    NTSTATUS ExitStatus;
+    TEB* Teb;
+    CLIENT_ID ClientId;
+    KAFFINITY AffinityMask;
+    LONG Priority;
+    LONG BasePriority;
+  };
+
+  using NtQueryInformationThreadFunction =
+      NTSTATUS (WINAPI*)(HANDLE, THREAD_INFORMATION_CLASS, PVOID, ULONG,
+                         PULONG);
+
+  const NtQueryInformationThreadFunction nt_query_information_thread =
+      reinterpret_cast<NtQueryInformationThreadFunction>(
+          ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"),
+                           "NtQueryInformationThread"));
+  if (!nt_query_information_thread)
+    return nullptr;
+
+  THREAD_BASIC_INFORMATION basic_info = {0};
+  NTSTATUS status =
+      nt_query_information_thread(thread_handle, ThreadBasicInformation,
+                                  &basic_info, sizeof(THREAD_BASIC_INFORMATION),
+                                  nullptr);
+  if (status != 0)
+    return nullptr;
+
+  return basic_info.Teb;
+}
+
+#if defined(_WIN64)
+// If the value at |pointer| points to the original stack, rewrite it to point
+// to the corresponding location in the copied stack.
+void RewritePointerIfInOriginalStack(uintptr_t top, uintptr_t bottom,
+                                     void* stack_copy, const void** pointer) {
+  const uintptr_t value = reinterpret_cast<uintptr_t>(*pointer);
+  if (value >= bottom && value < top) {
+    *pointer = reinterpret_cast<const void*>(
+        static_cast<unsigned char*>(stack_copy) + (value - bottom));
+  }
+}
+#endif
+
+// Rewrites possible pointers to locations within the stack to point to the
+// corresponding locations in the copy, and rewrites the non-volatile registers
+// in |context| likewise. This is necessary to handle stack frames with dynamic
+// stack allocation, where a pointer to the beginning of the dynamic allocation
+// area is stored on the stack and/or in a non-volatile register.
+//
+// Eager rewriting of anything that looks like a pointer to the stack, as done
+// in this function, does not adversely affect the stack unwinding. The only
+// other values on the stack the unwinding depends on are return addresses,
+// which should not point within the stack memory. The rewriting is guaranteed
+// to catch all pointers because the stacks are guaranteed by the ABI to be
+// sizeof(void*) aligned.
+//
+// Note: this function must not access memory in the original stack as it may
+// have been changed or deallocated by this point. This is why |top| and
+// |bottom| are passed as uintptr_t.
+void RewritePointersToStackMemory(uintptr_t top, uintptr_t bottom,
+                                  CONTEXT* context, void* stack_copy) {
+#if defined(_WIN64)
+  DWORD64 CONTEXT::* const nonvolatile_registers[] = {
+    &CONTEXT::R12,
+    &CONTEXT::R13,
+    &CONTEXT::R14,
+    &CONTEXT::R15,
+    &CONTEXT::Rdi,
+    &CONTEXT::Rsi,
+    &CONTEXT::Rbx,
+    &CONTEXT::Rbp,
+    &CONTEXT::Rsp
+  };
+
+  // Rewrite pointers in the context.
+  for (size_t i = 0; i < arraysize(nonvolatile_registers); ++i) {
+    DWORD64* const reg = &(context->*nonvolatile_registers[i]);
+    RewritePointerIfInOriginalStack(top, bottom, stack_copy,
+                                    reinterpret_cast<const void**>(reg));
+  }
+
+  // Rewrite pointers on the stack.
+  const void** start = reinterpret_cast<const void**>(stack_copy);
+  const void** end = reinterpret_cast<const void**>(
+      reinterpret_cast<char*>(stack_copy) + (top - bottom));
+  for (const void** loc = start; loc < end; ++loc)
+    RewritePointerIfInOriginalStack(top, bottom, stack_copy, loc);
+#endif
+}
+
+// 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[],
+                ScopedModuleHandle modules[]) {
+#ifdef _WIN64
+  Win32StackFrameUnwinder frame_unwinder;
+  int i = 0;
+  for (; (i < max_stack_size) && context->Rip; ++i) {
+    instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip);
+    if (!frame_unwinder.TryUnwind(context, &modules[i]))
+      return i;
+  }
+  return i;
+#else
+  return 0;
+#endif
+}
+
+// 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);
+}
+
+// ScopedDisablePriorityBoost -------------------------------------------------
+
+// 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_);
+}
+
+// ScopedSuspendThread --------------------------------------------------------
+
+// Suspends a thread for the lifetime of the object.
+class ScopedSuspendThread {
+ public:
+  ScopedSuspendThread(HANDLE thread_handle);
+  ~ScopedSuspendThread();
+
+  bool was_successful() const { return was_successful_; }
+
+ private:
+  HANDLE thread_handle_;
+  bool was_successful_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSuspendThread);
+};
+
+ScopedSuspendThread::ScopedSuspendThread(HANDLE thread_handle)
+    : thread_handle_(thread_handle),
+      was_successful_(::SuspendThread(thread_handle) != -1) {
+}
+
+ScopedSuspendThread::~ScopedSuspendThread() {
+  if (!was_successful_)
+    return;
+
+  // 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();
+}
+
+// Suspends the thread with |thread_handle|, copies its stack and resumes the
+// thread, then records the stack into |instruction_pointers|. Returns the size
+// of the stack.
+//
+// IMPORTANT NOTE: No allocations from the default heap may occur in the
+// ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or
+// other logging statements. Otherwise this code can deadlock on heap locks in
+// the default heap acquired by the target thread before it was suspended. This
+// is why we pass instruction pointers as preallocated arrays.
+int SuspendThreadAndRecordStack(HANDLE thread_handle,
+                                const void* base_address,
+                                void* stack_copy_buffer,
+                                size_t stack_copy_buffer_size,
+                                int max_stack_size,
+                                const void* instruction_pointers[],
+                                ScopedModuleHandle modules[],
+                                NativeStackSamplerTestDelegate* test_delegate) {
+  CONTEXT thread_context = {0};
+  thread_context.ContextFlags = CONTEXT_FULL;
+  // The stack bounds are saved to uintptr_ts for use outside
+  // ScopedSuspendThread, as the thread's memory is not safe to dereference
+  // beyond that point.
+  const uintptr_t top = reinterpret_cast<uintptr_t>(base_address);
+  uintptr_t bottom = 0u;
+
+  {
+    ScopedSuspendThread suspend_thread(thread_handle);
+
+    if (!suspend_thread.was_successful())
+      return 0;
+
+    if (!::GetThreadContext(thread_handle, &thread_context))
+      return 0;
+#if defined(_WIN64)
+    bottom = thread_context.Rsp;
+#else
+    bottom = thread_context.Esp;
+#endif
+
+    if ((top - bottom) > stack_copy_buffer_size)
+      return 0;
+
+    std::memcpy(stack_copy_buffer, reinterpret_cast<const void*>(bottom),
+                top - bottom);
+  }
+
+  if (test_delegate)
+    test_delegate->OnPreStackWalk();
+
+  RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer);
+
+  return RecordStack(&thread_context, max_stack_size, instruction_pointers,
+                     modules);
+}
+
+// NativeStackSamplerWin ------------------------------------------------------
+
+class NativeStackSamplerWin : public NativeStackSampler {
+ public:
+  NativeStackSamplerWin(win::ScopedHandle thread_handle,
+                        NativeStackSamplerTestDelegate* test_delegate);
+  ~NativeStackSamplerWin() override;
+
+  // StackSamplingProfiler::NativeStackSampler:
+  void ProfileRecordingStarting(
+      std::vector<StackSamplingProfiler::Module>* modules) override;
+  void RecordStackSample(StackSamplingProfiler::Sample* sample) override;
+  void ProfileRecordingStopped() override;
+
+ private:
+  enum {
+    // Intended to hold the largest stack used by Chrome. The default Win32
+    // reserved stack size is 1 MB and Chrome Windows threads currently always
+    // use the default, but this allows for expansion if it occurs. The size
+    // beyond the actual stack size consists of unallocated virtual memory pages
+    // so carries little cost (just a bit of wated address space).
+    kStackCopyBufferSize = 2 * 1024 * 1024
+  };
+
+  // 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 ScopedModuleHandle module_handles[],
+                    int stack_depth,
+                    StackSamplingProfiler::Sample* sample,
+                    std::vector<StackSamplingProfiler::Module>* modules);
+
+  win::ScopedHandle thread_handle_;
+
+  NativeStackSamplerTestDelegate* const test_delegate_;
+
+  // The stack base address corresponding to |thread_handle_|.
+  const void* const thread_stack_base_address_;
+
+  // Buffer to use for copies of the stack. We use the same buffer for all the
+  // samples to avoid the overhead of multiple allocations and frees.
+  const scoped_ptr<unsigned char[]> stack_copy_buffer_;
+
+  // 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,
+    NativeStackSamplerTestDelegate* test_delegate)
+    : thread_handle_(thread_handle.Take()), test_delegate_(test_delegate),
+      thread_stack_base_address_(
+          GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase),
+      stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) {
+}
+
+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_);
+
+  if (!stack_copy_buffer_)
+    return;
+
+  const int max_stack_size = 64;
+  const void* instruction_pointers[max_stack_size] = {0};
+  ScopedModuleHandle modules[max_stack_size];
+
+  int stack_depth = SuspendThreadAndRecordStack(thread_handle_.Get(),
+                                                thread_stack_base_address_,
+                                                stack_copy_buffer_.get(),
+                                                kStackCopyBufferSize,
+                                                max_stack_size,
+                                                instruction_pointers,
+                                                modules,
+                                                test_delegate_);
+  CopyToSample(instruction_pointers, modules, stack_depth, sample,
+               current_modules_);
+}
+
+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<uintptr_t>(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 ScopedModuleHandle module_handles[],
+    int stack_depth,
+    StackSamplingProfiler::Sample* sample,
+    std::vector<StackSamplingProfiler::Module>* modules) {
+  sample->clear();
+  sample->reserve(stack_depth);
+
+  for (int i = 0; i < stack_depth; ++i) {
+    sample->push_back(StackSamplingProfiler::Frame(
+        reinterpret_cast<uintptr_t>(instruction_pointers[i]),
+        GetModuleIndex(module_handles[i].Get(), modules)));
+  }
+}
+
+}  // namespace
+
+scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
+    PlatformThreadId thread_id,
+    NativeStackSamplerTestDelegate* test_delegate) {
+#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),
+        test_delegate));
+  }
+#endif
+  return scoped_ptr<NativeStackSampler>();
+}
+
+}  // namespace base
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
index 9da6628..52b412d 100644
--- a/base/profiler/stack_sampling_profiler.cc
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -5,120 +5,87 @@
 #include "base/profiler/stack_sampling_profiler.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/callback.h"
-#include "base/memory/singleton.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/profiler/native_stack_sampler.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.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 {
+// Used to ensure only one profiler is running at a time.
+LazyInstance<Lock> concurrent_profiling_lock = LAZY_INSTANCE_INITIALIZER;
+
+// AsyncRunner ----------------------------------------------------------------
+
+// Helper class to allow a profiler to be run completely asynchronously from the
+// initiator, without being concerned with the profiler's lifetime.
+class AsyncRunner {
  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);
+  // Sets up a profiler and arranges for it to be deleted on its completed
+  // callback.
+  static void Run(PlatformThreadId thread_id,
+                  const StackSamplingProfiler::SamplingParams& params,
+                  const StackSamplingProfiler::CompletedCallback& callback);
 
  private:
-  friend struct DefaultSingletonTraits<DefaultProfileProcessor>;
+  AsyncRunner();
 
-  DefaultProfileProcessor();
+  // Runs the callback and deletes the AsyncRunner instance.
+  static void RunCallbackAndDeleteInstance(
+      scoped_ptr<AsyncRunner> object_to_be_deleted,
+      const StackSamplingProfiler::CompletedCallback& callback,
+      scoped_refptr<SingleThreadTaskRunner> task_runner,
+      const StackSamplingProfiler::CallStackProfiles& profiles);
 
-  // Copies the pending profiles from |profiles_| into |profiles|, and clears
-  // |profiles_|. This function may be called on any thread.
-  void GetAndClearPendingProfiles(
-      StackSamplingProfiler::CallStackProfiles* profiles);
+  scoped_ptr<StackSamplingProfiler> profiler_;
 
-  // 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);
+  DISALLOW_COPY_AND_ASSIGN(AsyncRunner);
 };
 
-DefaultProfileProcessor::~DefaultProfileProcessor() {}
-
 // static
-DefaultProfileProcessor* DefaultProfileProcessor::GetInstance() {
-  return Singleton<DefaultProfileProcessor>::get();
+void AsyncRunner::Run(
+    PlatformThreadId thread_id,
+    const StackSamplingProfiler::SamplingParams& params,
+    const StackSamplingProfiler::CompletedCallback &callback) {
+  scoped_ptr<AsyncRunner> runner(new AsyncRunner);
+  AsyncRunner* temp_ptr = runner.get();
+  temp_ptr->profiler_.reset(
+      new StackSamplingProfiler(thread_id, params,
+                                Bind(&AsyncRunner::RunCallbackAndDeleteInstance,
+                                     Passed(&runner), callback,
+                                     ThreadTaskRunnerHandle::Get())));
+  // The callback won't be called until after Start(), so temp_ptr will still
+  // be valid here.
+  temp_ptr->profiler_->Start();
 }
 
-void DefaultProfileProcessor::SetCompletedCallback(CompletedCallback callback) {
-  {
-    AutoLock scoped_lock(callback_lock_);
-    default_completed_callback_ = callback;
-  }
+AsyncRunner::AsyncRunner() {}
 
-  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(
+void AsyncRunner::RunCallbackAndDeleteInstance(
+    scoped_ptr<AsyncRunner> object_to_be_deleted,
+    const StackSamplingProfiler::CompletedCallback& callback,
+    scoped_refptr<SingleThreadTaskRunner> task_runner,
     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_;
+  callback.Run(profiles);
+  // Delete the instance on the original calling thread.
+  task_runner->DeleteSoon(FROM_HERE, object_to_be_deleted.release());
 }
 
 }  // namespace
 
 // StackSamplingProfiler::Module ----------------------------------------------
 
-StackSamplingProfiler::Module::Module() : base_address(nullptr) {}
-StackSamplingProfiler::Module::Module(const void* base_address,
+StackSamplingProfiler::Module::Module() : base_address(0u) {}
+StackSamplingProfiler::Module::Module(uintptr_t base_address,
                                       const std::string& id,
                                       const FilePath& filename)
     : base_address(base_address), id(id), filename(filename) {}
@@ -127,17 +94,17 @@
 
 // StackSamplingProfiler::Frame -----------------------------------------------
 
-StackSamplingProfiler::Frame::Frame(const void* instruction_pointer,
+StackSamplingProfiler::Frame::Frame(uintptr_t instruction_pointer,
                                     size_t module_index)
-    : instruction_pointer(instruction_pointer),
-      module_index(module_index) {}
+    : instruction_pointer(instruction_pointer), module_index(module_index) {}
 
 StackSamplingProfiler::Frame::~Frame() {}
 
+StackSamplingProfiler::Frame::Frame() {}
+
 // StackSamplingProfiler::CallStackProfile ------------------------------------
 
-StackSamplingProfiler::CallStackProfile::CallStackProfile()
-    : preserve_sample_ordering(false), user_data(0) {}
+StackSamplingProfiler::CallStackProfile::CallStackProfile() {}
 
 StackSamplingProfiler::CallStackProfile::~CallStackProfile() {}
 
@@ -146,20 +113,25 @@
 StackSamplingProfiler::SamplingThread::SamplingThread(
     scoped_ptr<NativeStackSampler> native_sampler,
     const SamplingParams& params,
-    CompletedCallback completed_callback)
-    : native_sampler_(native_sampler.Pass()),
+    const CompletedCallback& completed_callback)
+    : native_sampler_(std::move(native_sampler)),
       params_(params),
       stop_event_(false, false),
-      completed_callback_(completed_callback) {
-}
+      completed_callback_(completed_callback) {}
 
 StackSamplingProfiler::SamplingThread::~SamplingThread() {}
 
 void StackSamplingProfiler::SamplingThread::ThreadMain() {
   PlatformThread::SetName("Chrome_SamplingProfilerThread");
 
+  // For now, just ignore any requests to profile while another profiler is
+  // working.
+  if (!concurrent_profiling_lock.Get().Try())
+    return;
+
   CallStackProfiles profiles;
   CollectProfiles(&profiles);
+  concurrent_profiling_lock.Get().Release();
   completed_callback_.Run(profiles);
 }
 
@@ -170,14 +142,14 @@
 // 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(
+void StackSamplingProfiler::SamplingThread::CollectProfile(
     CallStackProfile* profile,
-    TimeDelta* elapsed_time) {
+    TimeDelta* elapsed_time,
+    bool* was_stopped) {
   ElapsedTimer profile_timer;
-  CallStackProfile current_profile;
-  native_sampler_->ProfileRecordingStarting(&current_profile.modules);
-  current_profile.sampling_period = params_.sampling_interval;
-  bool burst_completed = true;
+  native_sampler_->ProfileRecordingStarting(&profile->modules);
+  profile->sampling_period = params_.sampling_interval;
+  *was_stopped = false;
   TimeDelta previous_elapsed_sample_time;
   for (int i = 0; i < params_.samples_per_burst; ++i) {
     if (i != 0) {
@@ -186,26 +158,19 @@
       if (stop_event_.TimedWait(
               std::max(params_.sampling_interval - previous_elapsed_sample_time,
                        TimeDelta()))) {
-        burst_completed = false;
+        *was_stopped = true;
         break;
       }
     }
     ElapsedTimer sample_timer;
-    current_profile.samples.push_back(Sample());
-    native_sampler_->RecordStackSample(&current_profile.samples.back());
+    profile->samples.push_back(Sample());
+    native_sampler_->RecordStackSample(&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;
+  profile->profile_duration = *elapsed_time;
   native_sampler_->ProfileRecordingStopped();
-
-  if (burst_completed)
-    *profile = current_profile;
-
-  return burst_completed;
 }
 
 // In an analogous manner to CollectProfile() and samples exceeding the expected
@@ -228,9 +193,13 @@
     }
 
     CallStackProfile profile;
-    if (!CollectProfile(&profile, &previous_elapsed_profile_time))
+    bool was_stopped = false;
+    CollectProfile(&profile, &previous_elapsed_profile_time, &was_stopped);
+    if (!profile.samples.empty())
+      profiles->push_back(profile);
+
+    if (was_stopped)
       return;
-    profiles->push_back(profile);
   }
 }
 
@@ -245,19 +214,23 @@
       bursts(1),
       burst_interval(TimeDelta::FromMilliseconds(10000)),
       samples_per_burst(300),
-      sampling_interval(TimeDelta::FromMilliseconds(100)),
-      preserve_sample_ordering(false),
-      user_data(0) {
+      sampling_interval(TimeDelta::FromMilliseconds(100)) {
 }
 
-StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
-                                             const SamplingParams& params)
-    : thread_id_(thread_id), params_(params) {}
+StackSamplingProfiler::StackSamplingProfiler(
+    PlatformThreadId thread_id,
+    const SamplingParams& params,
+    const CompletedCallback& callback)
+    : StackSamplingProfiler(thread_id, params, callback, nullptr) {}
 
-StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
-                                             const SamplingParams& params,
-                                             CompletedCallback callback)
-    : thread_id_(thread_id), params_(params), completed_callback_(callback) {}
+StackSamplingProfiler::StackSamplingProfiler(
+    PlatformThreadId thread_id,
+    const SamplingParams& params,
+    const CompletedCallback& callback,
+    NativeStackSamplerTestDelegate* test_delegate)
+    : thread_id_(thread_id), params_(params), completed_callback_(callback),
+      test_delegate_(test_delegate) {
+}
 
 StackSamplingProfiler::~StackSamplingProfiler() {
   Stop();
@@ -265,18 +238,26 @@
     PlatformThread::Join(sampling_thread_handle_);
 }
 
+// static
+void StackSamplingProfiler::StartAndRunAsync(
+    PlatformThreadId thread_id,
+    const SamplingParams& params,
+    const CompletedCallback& callback) {
+  CHECK(ThreadTaskRunnerHandle::Get());
+  AsyncRunner::Run(thread_id, params, callback);
+}
+
 void StackSamplingProfiler::Start() {
+  if (completed_callback_.is_null())
+    return;
+
   scoped_ptr<NativeStackSampler> native_sampler =
-      NativeStackSampler::Create(thread_id_);
+      NativeStackSampler::Create(thread_id_, test_delegate_);
   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));
+  sampling_thread_.reset(new SamplingThread(std::move(native_sampler), params_,
+                                            completed_callback_));
   if (!PlatformThread::Create(0, sampling_thread_.get(),
                               &sampling_thread_handle_))
     sampling_thread_.reset();
@@ -287,12 +268,6 @@
     sampling_thread_->Stop();
 }
 
-// static
-void StackSamplingProfiler::SetDefaultCompletedCallback(
-    CompletedCallback callback) {
-  DefaultProfileProcessor::GetInstance()->SetCompletedCallback(callback);
-}
-
 // StackSamplingProfiler::Frame global functions ------------------------------
 
 bool operator==(const StackSamplingProfiler::Frame &a,
diff --git a/base/profiler/stack_sampling_profiler.h b/base/profiler/stack_sampling_profiler.h
index 9d52f27..e9b1804 100644
--- a/base/profiler/stack_sampling_profiler.h
+++ b/base/profiler/stack_sampling_profiler.h
@@ -20,6 +20,7 @@
 namespace base {
 
 class NativeStackSampler;
+class NativeStackSamplerTestDelegate;
 
 // StackSamplingProfiler periodically stops a thread to sample its stack, for
 // the purpose of collecting information about which code paths are
@@ -49,14 +50,9 @@
 // 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.
+// When all call stack profiles are complete, or the profiler is stopped, the
+// completed callback is called from a thread created by the profiler with the
+// collected profiles.
 //
 // The results of the profiling are passed to the completed callback and consist
 // of a vector of CallStackProfiles. Each CallStackProfile corresponds to a
@@ -68,12 +64,13 @@
   // 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,
+    Module(uintptr_t base_address,
+           const std::string& id,
            const FilePath& filename);
     ~Module();
 
     // Points to the base address of the module.
-    const void* base_address;
+    uintptr_t base_address;
 
     // An opaque binary string that uniquely identifies a particular program
     // version with high probability. This is parsed from headers of the loaded
@@ -93,11 +90,14 @@
     // Identifies an unknown module.
     static const size_t kUnknownModuleIndex = static_cast<size_t>(-1);
 
-    Frame(const void* instruction_pointer, size_t module_index);
+    Frame(uintptr_t instruction_pointer, size_t module_index);
     ~Frame();
 
+    // Default constructor to satisfy IPC macros. Do not use explicitly.
+    Frame();
+
     // The sampled instruction pointer within the function.
-    const void* instruction_pointer;
+    uintptr_t instruction_pointer;
 
     // Index of the module in CallStackProfile::modules. We don't represent
     // module state directly here to save space.
@@ -120,13 +120,6 @@
 
     // 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>;
@@ -152,13 +145,6 @@
     // 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.
@@ -171,33 +157,34 @@
   // 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|.
+  // Creates a profiler that sends completed profiles to |callback|. The second
+  // constructor is for test purposes.
   StackSamplingProfiler(PlatformThreadId thread_id,
                         const SamplingParams& params,
-                        CompletedCallback callback);
+                        const CompletedCallback& callback);
+  StackSamplingProfiler(PlatformThreadId thread_id,
+                        const SamplingParams& params,
+                        const CompletedCallback& callback,
+                        NativeStackSamplerTestDelegate* test_delegate);
+  // Stops any profiling currently taking place before destroying the profiler.
   ~StackSamplingProfiler();
 
+  // The fire-and-forget interface: starts a profiler and allows it to complete
+  // without the caller needing to manage the profiler lifetime. May be invoked
+  // from any thread, but requires that the calling thread has a message loop.
+  static void StartAndRunAsync(PlatformThreadId thread_id,
+                               const SamplingParams& params,
+                               const CompletedCallback& callback);
+
   // 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.
+  // specified in the SamplingParams are completed or the profiler is destroyed,
+  // whichever occurs first.
   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.
@@ -208,7 +195,7 @@
     // |completed_callback| must be callable on any thread.
     SamplingThread(scoped_ptr<NativeStackSampler> native_sampler,
                    const SamplingParams& params,
-                   CompletedCallback completed_callback);
+                   const CompletedCallback& completed_callback);
     ~SamplingThread() override;
 
     // PlatformThread::Delegate:
@@ -217,14 +204,15 @@
     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 |profile| from a single burst. If the profiler was stopped
+    // during collection, sets |was_stopped| and provides the set of samples
+    // collected up to that point.
+    void CollectProfile(CallStackProfile* profile, TimeDelta* elapsed_time,
+                        bool* was_stopped);
 
     // 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.
+    // stopped. If stopped before complete, the last profile in
+    // |call_stack_profiles| may contain a partial burst.
     void CollectProfiles(CallStackProfiles* profiles);
 
     scoped_ptr<NativeStackSampler> native_sampler_;
@@ -249,6 +237,9 @@
 
   const CompletedCallback completed_callback_;
 
+  // Stored until it can be passed to the NativeStackSampler created in Start().
+  NativeStackSamplerTestDelegate* const test_delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
 };
 
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc
index 5ade15a..2ba769f 100644
--- a/base/profiler/stack_sampling_profiler_unittest.cc
+++ b/base/profiler/stack_sampling_profiler_unittest.cc
@@ -2,16 +2,44 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <cstdlib>
+
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "base/native_library.h"
 #include "base/path_service.h"
+#include "base/profiler/native_stack_sampler.h"
 #include "base/profiler/stack_sampling_profiler.h"
+#include "base/run_loop.h"
+#include "base/scoped_native_library.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_WIN)
+#include <intrin.h>
+#include <malloc.h>
+#include <windows.h>
+#else
+#include <alloca.h>
+#endif
+
+// STACK_SAMPLING_PROFILER_SUPPORTED is used to conditionally enable the tests
+// below for supported platforms (currently Win x64).
+#if defined(_WIN64)
+#define STACK_SAMPLING_PROFILER_SUPPORTED 1
+#endif
+
+#if defined(OS_WIN)
+#pragma intrinsic(_ReturnAddress)
+#endif
+
 namespace base {
 
 using SamplingParams = StackSamplingProfiler::SamplingParams;
@@ -23,11 +51,37 @@
 
 namespace {
 
+// Configuration for the frames that appear on the stack.
+struct StackConfiguration {
+  enum Config { NORMAL, WITH_ALLOCA, WITH_OTHER_LIBRARY };
+
+  explicit StackConfiguration(Config config)
+      : StackConfiguration(config, nullptr) {
+    EXPECT_NE(config, WITH_OTHER_LIBRARY);
+  }
+
+  StackConfiguration(Config config, NativeLibrary library)
+      : config(config), library(library) {
+    EXPECT_TRUE(config != WITH_OTHER_LIBRARY || library);
+  }
+
+  Config config;
+
+  // Only used if config == WITH_OTHER_LIBRARY.
+  NativeLibrary library;
+};
+
+// Signature for a target function that is expected to appear in the stack. See
+// SignalAndWaitUntilSignaled() below. The return value should be a program
+// counter pointer near the end of the function.
+using TargetFunction = const void*(*)(WaitableEvent*, WaitableEvent*,
+                                      const StackConfiguration*);
+
 // 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();
+  TargetThread(const StackConfiguration& stack_config);
 
   // PlatformThread::Delegate:
   void ThreadMain() override;
@@ -41,30 +95,76 @@
   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);
+  // WaitForThreadStart() and SignalThreadToFinish() when invoked with
+  // |thread_started_event_| and |finish_event_|. Returns a program counter
+  // value near the end of the function. May be invoked with null WaitableEvents
+  // to just return the program counter.
+  //
+  // 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 const void* SignalAndWaitUntilSignaled(
+      WaitableEvent* thread_started_event,
+      WaitableEvent* finish_event,
+      const StackConfiguration* stack_config);
+
+  // Calls into SignalAndWaitUntilSignaled() after allocating memory on the
+  // stack with alloca.
+  static const void* CallWithAlloca(WaitableEvent* thread_started_event,
+                                    WaitableEvent* finish_event,
+                                    const StackConfiguration* stack_config);
+
+  // Calls into SignalAndWaitUntilSignaled() via a function in
+  // base_profiler_test_support_library.
+  static const void* CallThroughOtherLibrary(
+      WaitableEvent* thread_started_event,
+      WaitableEvent* finish_event,
+      const StackConfiguration* stack_config);
 
   PlatformThreadId id() const { return id_; }
 
  private:
+  struct TargetFunctionArgs {
+    WaitableEvent* thread_started_event;
+    WaitableEvent* finish_event;
+    const StackConfiguration* stack_config;
+  };
+
+  // Callback function to be provided when calling through the other library.
+  static void OtherLibraryCallback(void *arg);
+
+  // Returns the current program counter, or a value very close to it.
+  static const void* GetProgramCounter();
+
   WaitableEvent thread_started_event_;
   WaitableEvent finish_event_;
   PlatformThreadId id_;
+  const StackConfiguration stack_config_;
 
   DISALLOW_COPY_AND_ASSIGN(TargetThread);
 };
 
-TargetThread::TargetThread()
+TargetThread::TargetThread(const StackConfiguration& stack_config)
     : thread_started_event_(false, false), finish_event_(false, false),
-      id_(0) {}
+      id_(0), stack_config_(stack_config) {}
 
 void TargetThread::ThreadMain() {
   id_ = PlatformThread::CurrentId();
-  SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_);
+  switch (stack_config_.config) {
+    case StackConfiguration::NORMAL:
+      SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_,
+                                 &stack_config_);
+      break;
+
+    case StackConfiguration::WITH_ALLOCA:
+      CallWithAlloca(&thread_started_event_, &finish_event_, &stack_config_);
+      break;
+
+    case StackConfiguration::WITH_OTHER_LIBRARY:
+      CallThroughOtherLibrary(&thread_started_event_, &finish_event_,
+                              &stack_config_);
+      break;
+  }
 }
 
 void TargetThread::WaitForThreadStart() {
@@ -77,14 +177,127 @@
 
 // static
 // Disable inlining for this function so that it gets its own stack frame.
-NOINLINE void TargetThread::SignalAndWaitUntilSignaled(
+NOINLINE const 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);
+    WaitableEvent* finish_event,
+    const StackConfiguration* stack_config) {
+  if (thread_started_event && finish_event) {
+    thread_started_event->Signal();
+    finish_event->Wait();
+  }
+
+  // Volatile to prevent a tail call to GetProgramCounter().
+  const void* volatile program_counter = GetProgramCounter();
+  return program_counter;
+}
+
+// static
+// Disable inlining for this function so that it gets its own stack frame.
+NOINLINE const void* TargetThread::CallWithAlloca(
+    WaitableEvent* thread_started_event,
+    WaitableEvent* finish_event,
+    const StackConfiguration* stack_config) {
+  const size_t alloca_size = 100;
+  // Memset to 0 to generate a clean failure.
+  std::memset(alloca(alloca_size), 0, alloca_size);
+
+  SignalAndWaitUntilSignaled(thread_started_event, finish_event, stack_config);
+
+  // Volatile to prevent a tail call to GetProgramCounter().
+  const void* volatile program_counter = GetProgramCounter();
+  return program_counter;
+}
+
+// static
+NOINLINE const void* TargetThread::CallThroughOtherLibrary(
+    WaitableEvent* thread_started_event,
+    WaitableEvent* finish_event,
+    const StackConfiguration* stack_config) {
+  if (stack_config) {
+    // A function whose arguments are a function accepting void*, and a void*.
+    using InvokeCallbackFunction = void(*)(void (*)(void*), void*);
+    EXPECT_TRUE(stack_config->library);
+    InvokeCallbackFunction function = reinterpret_cast<InvokeCallbackFunction>(
+        GetFunctionPointerFromNativeLibrary(stack_config->library,
+                                            "InvokeCallbackFunction"));
+    EXPECT_TRUE(function);
+
+    TargetFunctionArgs args = {
+      thread_started_event,
+      finish_event,
+      stack_config
+    };
+    (*function)(&OtherLibraryCallback, &args);
+  }
+
+  // Volatile to prevent a tail call to GetProgramCounter().
+  const void* volatile program_counter = GetProgramCounter();
+  return program_counter;
+}
+
+// static
+void TargetThread::OtherLibraryCallback(void *arg) {
+  const TargetFunctionArgs* args = static_cast<TargetFunctionArgs*>(arg);
+  SignalAndWaitUntilSignaled(args->thread_started_event, args->finish_event,
+                             args->stack_config);
+  // Prevent tail call.
+  volatile int i = 0;
+  ALLOW_UNUSED_LOCAL(i);
+}
+
+// static
+// Disable inlining for this function so that it gets its own stack frame.
+NOINLINE const void* TargetThread::GetProgramCounter() {
+#if defined(OS_WIN)
+  return _ReturnAddress();
+#else
+  return __builtin_return_address(0);
+#endif
+}
+
+// Loads the other library, which defines a function to be called in the
+// WITH_OTHER_LIBRARY configuration.
+NativeLibrary LoadOtherLibrary() {
+  // The lambda gymnastics works around the fact that we can't use ASSERT_*
+  // macros in a function returning non-null.
+  const auto load = [](NativeLibrary* library) {
+    FilePath other_library_path;
+    ASSERT_TRUE(PathService::Get(DIR_EXE, &other_library_path));
+    other_library_path = other_library_path.Append(FilePath::FromUTF16Unsafe(
+        GetNativeLibraryName(ASCIIToUTF16(
+            "base_profiler_test_support_library"))));
+    NativeLibraryLoadError load_error;
+    *library = LoadNativeLibrary(other_library_path, &load_error);
+    ASSERT_TRUE(*library) << "error loading " << other_library_path.value()
+                          << ": " << load_error.ToString();
+  };
+
+  NativeLibrary library = nullptr;
+  load(&library);
+  return library;
+}
+
+// Unloads |library| and returns when it has completed unloading. Unloading a
+// library is asynchronous on Windows, so simply calling UnloadNativeLibrary()
+// is insufficient to ensure it's been unloaded.
+void SynchronousUnloadNativeLibrary(NativeLibrary library) {
+  UnloadNativeLibrary(library);
+#if defined(OS_WIN)
+  // NativeLibrary is a typedef for HMODULE, which is actually the base address
+  // of the module.
+  uintptr_t module_base_address = reinterpret_cast<uintptr_t>(library);
+  HMODULE module_handle;
+  // Keep trying to get the module handle until the call fails.
+  while (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                             GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                             reinterpret_cast<LPCTSTR>(module_base_address),
+                             &module_handle) ||
+         ::GetLastError() != ERROR_MOD_NOT_FOUND) {
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+  }
+#else
+  NOTIMPLEMENTED();
+#endif
 }
 
 // Called on the profiler thread when complete, to collect profiles.
@@ -107,8 +320,9 @@
 // SignalAndWaitUntilSignaled(). Performs all necessary target thread startup
 // and shutdown work before and afterward.
 template <class Function>
-void WithTargetThread(Function function) {
-  TargetThread target_thread;
+void WithTargetThread(Function function,
+                      const StackConfiguration& stack_config) {
+  TargetThread target_thread(stack_config);
   PlatformThreadHandle target_thread_handle;
   EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
 
@@ -121,12 +335,16 @@
   PlatformThread::Join(target_thread_handle);
 }
 
+template <class Function>
+void WithTargetThread(Function function) {
+  WithTargetThread(function, StackConfiguration(StackConfiguration::NORMAL));
+}
+
 // 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) {
+void CaptureProfiles(const SamplingParams& params, TimeDelta profiler_wait_time,
+                     CallStackProfiles* profiles) {
   profiles->clear();
 
   WithTargetThread([&params, profiles, profiler_wait_time](
@@ -143,43 +361,6 @@
   });
 }
 
-// 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
@@ -203,18 +384,19 @@
 }
 
 // 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.
+// frame that has an instruction pointer within |target_function|. 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);
+    TargetFunction target_function) {
+  uintptr_t function_start = reinterpret_cast<uintptr_t>(
+      MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+          target_function)));
+  uintptr_t function_end =
+      reinterpret_cast<uintptr_t>(target_function(nullptr, nullptr, nullptr));
   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)))
+    if ((it->instruction_pointer >= function_start) &&
+        (it->instruction_pointer <= function_end))
       return it;
   }
   return sample.end();
@@ -227,7 +409,7 @@
   std::string output;
   for (const Frame& frame: sample) {
     output += StringPrintf(
-        "0x%p %s\n", frame.instruction_pointer,
+        "0x%p %s\n", reinterpret_cast<const void*>(frame.instruction_pointer),
         modules[frame.module_index].filename.AsUTF8Unsafe().c_str());
   }
   return output;
@@ -237,15 +419,154 @@
 // TimeDelta::Max() but https://crbug.com/465948.
 TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
 
+// Tests the scenario where the library is unloaded after copying the stack, but
+// before walking it. If |wait_until_unloaded| is true, ensures that the
+// asynchronous library loading has completed before walking the stack. If
+// false, the unloading may still be occurring during the stack walk.
+void TestLibraryUnload(bool wait_until_unloaded) {
+  // Test delegate that supports intervening between the copying of the stack
+  // and the walking of the stack.
+  class StackCopiedSignaler : public NativeStackSamplerTestDelegate {
+   public:
+    StackCopiedSignaler(WaitableEvent* stack_copied,
+                        WaitableEvent* start_stack_walk,
+                        bool wait_to_walk_stack)
+        : stack_copied_(stack_copied), start_stack_walk_(start_stack_walk),
+          wait_to_walk_stack_(wait_to_walk_stack) {
+    }
+
+    void OnPreStackWalk() override {
+      stack_copied_->Signal();
+      if (wait_to_walk_stack_)
+        start_stack_walk_->Wait();
+    }
+
+   private:
+    WaitableEvent* const stack_copied_;
+    WaitableEvent* const start_stack_walk_;
+    const bool wait_to_walk_stack_;
+  };
+
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(0);
+  params.samples_per_burst = 1;
+
+  NativeLibrary other_library = LoadOtherLibrary();
+  TargetThread target_thread(StackConfiguration(
+      StackConfiguration::WITH_OTHER_LIBRARY,
+      other_library));
+
+  PlatformThreadHandle target_thread_handle;
+  EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
+
+  target_thread.WaitForThreadStart();
+
+  WaitableEvent sampling_thread_completed(true, false);
+  std::vector<CallStackProfile> profiles;
+  const StackSamplingProfiler::CompletedCallback callback =
+      Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles),
+           Unretained(&sampling_thread_completed));
+  WaitableEvent stack_copied(true, false);
+  WaitableEvent start_stack_walk(true, false);
+  StackCopiedSignaler test_delegate(&stack_copied, &start_stack_walk,
+                                    wait_until_unloaded);
+  StackSamplingProfiler profiler(target_thread.id(), params, callback,
+                                 &test_delegate);
+
+  profiler.Start();
+
+  // Wait for the stack to be copied and the target thread to be resumed.
+  stack_copied.Wait();
+
+  // Cause the target thread to finish, so that it's no longer executing code in
+  // the library we're about to unload.
+  target_thread.SignalThreadToFinish();
+  PlatformThread::Join(target_thread_handle);
+
+  // Unload the library now that it's not being used.
+  if (wait_until_unloaded)
+    SynchronousUnloadNativeLibrary(other_library);
+  else
+    UnloadNativeLibrary(other_library);
+
+  // Let the stack walk commence after unloading the library, if we're waiting
+  // on that event.
+  start_stack_walk.Signal();
+
+  // Wait for the sampling thread to complete and fill out |profiles|.
+  sampling_thread_completed.Wait();
+
+  // Look up the sample.
+  ASSERT_EQ(1u, profiles.size());
+  const CallStackProfile& profile = profiles[0];
+  ASSERT_EQ(1u, profile.samples.size());
+  const Sample& sample = profile.samples[0];
+
+  // Check that the stack contains a frame for
+  // TargetThread::SignalAndWaitUntilSignaled().
+  Sample::const_iterator end_frame = FindFirstFrameWithinFunction(
+      sample,
+      &TargetThread::SignalAndWaitUntilSignaled);
+  ASSERT_TRUE(end_frame != sample.end())
+      << "Function at "
+      << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+          &TargetThread::SignalAndWaitUntilSignaled))
+      << " was not found in stack:\n"
+      << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+  if (wait_until_unloaded) {
+    // The stack should look like this, resulting one frame after
+    // SignalAndWaitUntilSignaled. The frame in the now-unloaded library is not
+    // recorded since we can't get module information.
+    //
+    // ... WaitableEvent and system frames ...
+    // TargetThread::SignalAndWaitUntilSignaled
+    // TargetThread::OtherLibraryCallback
+    EXPECT_EQ(2, sample.end() - end_frame)
+        << "Stack:\n"
+        << FormatSampleForDiagnosticOutput(sample, profile.modules);
+  } else {
+    // We didn't wait for the asynchonous unloading to complete, so the results
+    // are non-deterministic: if the library finished unloading we should have
+    // the same stack as |wait_until_unloaded|, if not we should have the full
+    // stack. The important thing is that we should not crash.
+
+    if ((sample.end() - 1) - end_frame == 2) {
+      // This is the same case as |wait_until_unloaded|.
+      return;
+    }
+
+    // Check that the stack contains a frame for
+    // TargetThread::CallThroughOtherLibrary().
+    Sample::const_iterator other_library_frame = FindFirstFrameWithinFunction(
+        sample,
+        &TargetThread::CallThroughOtherLibrary);
+    ASSERT_TRUE(other_library_frame != sample.end())
+        << "Function at "
+        << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+            &TargetThread::CallThroughOtherLibrary))
+        << " was not found in stack:\n"
+        << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+    // The stack should look like this, resulting in three frames between
+    // SignalAndWaitUntilSignaled and CallThroughOtherLibrary:
+    //
+    // ... WaitableEvent and system frames ...
+    // TargetThread::SignalAndWaitUntilSignaled
+    // TargetThread::OtherLibraryCallback
+    // InvokeCallbackFunction (in other library)
+    // TargetThread::CallThroughOtherLibrary
+    EXPECT_EQ(3, other_library_frame - end_frame)
+        << "Stack:\n"
+        << FormatSampleForDiagnosticOutput(sample, profile.modules);
+  }
+}
+
 }  // 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)
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
 #define MAYBE_Basic Basic
 #else
 #define MAYBE_Basic DISABLED_Basic
@@ -254,11 +575,9 @@
   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());
+  CaptureProfiles(params, AVeryLongTimeDelta(), &profiles);
 
   // Check that the profile and samples sizes are correct, and the module
   // indices are in range.
@@ -271,24 +590,17 @@
     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);
+      &TargetThread::SignalAndWaitUntilSignaled);
   ASSERT_TRUE(loc != sample.end())
       << "Function at "
-      << MaybeFixupFunctionAddressForILT(
-          reinterpret_cast<const void*>(
-              &TargetThread::SignalAndWaitUntilSignaled))
+      << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+          &TargetThread::SignalAndWaitUntilSignaled))
       << " was not found in stack:\n"
       << FormatSampleForDiagnosticOutput(sample, profile.modules);
   FilePath executable_path;
@@ -296,9 +608,95 @@
   EXPECT_EQ(executable_path, profile.modules[loc->module_index].filename);
 }
 
+// Checks that the profiler handles stacks containing dynamically-allocated
+// stack memory.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_Alloca Alloca
+#else
+#define MAYBE_Alloca DISABLED_Alloca
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_Alloca) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(0);
+  params.samples_per_burst = 1;
+
+  std::vector<CallStackProfile> profiles;
+  WithTargetThread([&params, &profiles](
+      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.Wait();
+  }, StackConfiguration(StackConfiguration::WITH_ALLOCA));
+
+  // Look up the sample.
+  ASSERT_EQ(1u, profiles.size());
+  const CallStackProfile& profile = profiles[0];
+  ASSERT_EQ(1u, profile.samples.size());
+  const Sample& sample = profile.samples[0];
+
+  // Check that the stack contains a frame for
+  // TargetThread::SignalAndWaitUntilSignaled().
+  Sample::const_iterator end_frame = FindFirstFrameWithinFunction(
+      sample,
+      &TargetThread::SignalAndWaitUntilSignaled);
+  ASSERT_TRUE(end_frame != sample.end())
+      << "Function at "
+      << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+          &TargetThread::SignalAndWaitUntilSignaled))
+      << " was not found in stack:\n"
+      << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+  // Check that the stack contains a frame for TargetThread::CallWithAlloca().
+  Sample::const_iterator alloca_frame = FindFirstFrameWithinFunction(
+      sample,
+      &TargetThread::CallWithAlloca);
+  ASSERT_TRUE(alloca_frame != sample.end())
+      << "Function at "
+      << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+          &TargetThread::CallWithAlloca))
+      << " was not found in stack:\n"
+      << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+  // These frames should be adjacent on the stack.
+  EXPECT_EQ(1, alloca_frame - end_frame)
+      << "Stack:\n"
+      << FormatSampleForDiagnosticOutput(sample, profile.modules);
+}
+
+// Checks that the fire-and-forget interface works.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_StartAndRunAsync StartAndRunAsync
+#else
+#define MAYBE_StartAndRunAsync DISABLED_StartAndRunAsync
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StartAndRunAsync) {
+  // StartAndRunAsync requires the caller to have a message loop.
+  MessageLoop message_loop;
+
+  SamplingParams params;
+  params.samples_per_burst = 1;
+
+  CallStackProfiles profiles;
+  WithTargetThread([&params, &profiles](PlatformThreadId target_thread_id) {
+    WaitableEvent sampling_thread_completed(false, false);
+    const StackSamplingProfiler::CompletedCallback callback =
+        Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles),
+             Unretained(&sampling_thread_completed));
+    StackSamplingProfiler::StartAndRunAsync(target_thread_id, params, callback);
+    RunLoop().RunUntilIdle();
+    sampling_thread_completed.Wait();
+  });
+
+  ASSERT_EQ(1u, profiles.size());
+}
+
 // Checks that the expected number of profiles and samples are present in the
 // call stack profiles produced.
-#if defined(_WIN64)
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
 #define MAYBE_MultipleProfilesAndSamples MultipleProfilesAndSamples
 #else
 #define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples
@@ -311,7 +709,7 @@
   params.samples_per_burst = 3;
 
   std::vector<CallStackProfile> profiles;
-  CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta());
+  CaptureProfiles(params, AVeryLongTimeDelta(), &profiles);
 
   ASSERT_EQ(2u, profiles.size());
   EXPECT_EQ(3u, profiles[0].samples.size());
@@ -320,7 +718,7 @@
 
 // Checks that no call stack profiles are captured if the profiling is stopped
 // during the initial delay.
-#if defined(_WIN64)
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
 #define MAYBE_StopDuringInitialDelay StopDuringInitialDelay
 #else
 #define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay
@@ -330,15 +728,14 @@
   params.initial_delay = TimeDelta::FromSeconds(60);
 
   std::vector<CallStackProfile> profiles;
-  CaptureProfilesWithObjectCallback(params, &profiles,
-                                    TimeDelta::FromMilliseconds(0));
+  CaptureProfiles(params, TimeDelta::FromMilliseconds(0), &profiles);
 
   EXPECT_TRUE(profiles.empty());
 }
 
 // Checks that the single completed call stack profile is captured if the
 // profiling is stopped between bursts.
-#if defined(_WIN64)
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
 #define MAYBE_StopDuringInterBurstInterval StopDuringInterBurstInterval
 #else
 #define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval
@@ -351,15 +748,14 @@
   params.samples_per_burst = 1;
 
   std::vector<CallStackProfile> profiles;
-  CaptureProfilesWithObjectCallback(params, &profiles,
-                                    TimeDelta::FromMilliseconds(50));
+  CaptureProfiles(params, TimeDelta::FromMilliseconds(50), &profiles);
 
   ASSERT_EQ(1u, profiles.size());
   EXPECT_EQ(1u, profiles[0].samples.size());
 }
 
-// Checks that only completed call stack profiles are captured.
-#if defined(_WIN64)
+// Checks that incomplete call stack profiles are captured.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
 #define MAYBE_StopDuringInterSampleInterval StopDuringInterSampleInterval
 #else
 #define MAYBE_StopDuringInterSampleInterval \
@@ -371,54 +767,14 @@
   params.samples_per_burst = 2;
 
   std::vector<CallStackProfile> profiles;
-  CaptureProfilesWithObjectCallback(params, &profiles,
-                                    TimeDelta::FromMilliseconds(50));
+  CaptureProfiles(params, TimeDelta::FromMilliseconds(50), &profiles);
 
-  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());
+  ASSERT_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)
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
 #define MAYBE_DestroyProfilerWhileProfiling DestroyProfilerWhileProfiling
 #else
 #define MAYBE_DestroyProfilerWhileProfiling \
@@ -442,4 +798,165 @@
   });
 }
 
+// Checks that the same profiler may be run multiple times.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_CanRunMultipleTimes CanRunMultipleTimes
+#else
+#define MAYBE_CanRunMultipleTimes DISABLED_CanRunMultipleTimes
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_CanRunMultipleTimes) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(0);
+  params.samples_per_burst = 1;
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfiles(params, AVeryLongTimeDelta(), &profiles);
+  ASSERT_EQ(1u, profiles.size());
+
+  profiles.clear();
+  CaptureProfiles(params, AVeryLongTimeDelta(), &profiles);
+  ASSERT_EQ(1u, profiles.size());
+}
+
+// Checks that requests to start profiling while another profile is taking place
+// are ignored.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_ConcurrentProfiling ConcurrentProfiling
+#else
+#define MAYBE_ConcurrentProfiling DISABLED_ConcurrentProfiling
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_ConcurrentProfiling) {
+  WithTargetThread([](PlatformThreadId target_thread_id) {
+    SamplingParams params[2];
+    params[0].initial_delay = TimeDelta::FromMilliseconds(10);
+    params[0].sampling_interval = TimeDelta::FromMilliseconds(0);
+    params[0].samples_per_burst = 1;
+
+    params[1].sampling_interval = TimeDelta::FromMilliseconds(0);
+    params[1].samples_per_burst = 1;
+
+    CallStackProfiles profiles[2];
+    ScopedVector<WaitableEvent> sampling_completed;
+    ScopedVector<StackSamplingProfiler> profiler;
+    for (int i = 0; i < 2; ++i) {
+      sampling_completed.push_back(new WaitableEvent(false, false));
+      const StackSamplingProfiler::CompletedCallback callback =
+          Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles[i]),
+               Unretained(sampling_completed[i]));
+      profiler.push_back(
+          new StackSamplingProfiler(target_thread_id, params[i], callback));
+    }
+
+    profiler[0]->Start();
+    profiler[1]->Start();
+
+    // Wait for one profiler to finish.
+    size_t completed_profiler =
+        WaitableEvent::WaitMany(&sampling_completed[0], 2);
+    EXPECT_EQ(1u, profiles[completed_profiler].size());
+
+    size_t other_profiler = 1 - completed_profiler;
+    // Give the other profiler a chance to run and observe that it hasn't.
+    EXPECT_FALSE(sampling_completed[other_profiler]->TimedWait(
+        TimeDelta::FromMilliseconds(25)));
+
+    // Start the other profiler again and it should run.
+    profiler[other_profiler]->Start();
+    sampling_completed[other_profiler]->Wait();
+    EXPECT_EQ(1u, profiles[other_profiler].size());
+  });
+}
+
+// Checks that a stack that runs through another library produces a stack with
+// the expected functions.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_OtherLibrary OtherLibrary
+#else
+#define MAYBE_OtherLibrary DISABLED_OtherLibrary
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_OtherLibrary) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(0);
+  params.samples_per_burst = 1;
+
+  std::vector<CallStackProfile> profiles;
+  {
+    ScopedNativeLibrary other_library(LoadOtherLibrary());
+    WithTargetThread([&params, &profiles](
+        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.Wait();
+    }, StackConfiguration(StackConfiguration::WITH_OTHER_LIBRARY,
+                          other_library.get()));
+  }
+
+  // Look up the sample.
+  ASSERT_EQ(1u, profiles.size());
+  const CallStackProfile& profile = profiles[0];
+  ASSERT_EQ(1u, profile.samples.size());
+  const Sample& sample = profile.samples[0];
+
+  // Check that the stack contains a frame for
+  // TargetThread::CallThroughOtherLibrary().
+  Sample::const_iterator other_library_frame = FindFirstFrameWithinFunction(
+      sample,
+      &TargetThread::CallThroughOtherLibrary);
+  ASSERT_TRUE(other_library_frame != sample.end())
+      << "Function at "
+      << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+          &TargetThread::CallThroughOtherLibrary))
+      << " was not found in stack:\n"
+      << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+  // Check that the stack contains a frame for
+  // TargetThread::SignalAndWaitUntilSignaled().
+  Sample::const_iterator end_frame = FindFirstFrameWithinFunction(
+      sample,
+      &TargetThread::SignalAndWaitUntilSignaled);
+  ASSERT_TRUE(end_frame != sample.end())
+      << "Function at "
+      << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+          &TargetThread::SignalAndWaitUntilSignaled))
+      << " was not found in stack:\n"
+      << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+  // The stack should look like this, resulting in three frames between
+  // SignalAndWaitUntilSignaled and CallThroughOtherLibrary:
+  //
+  // ... WaitableEvent and system frames ...
+  // TargetThread::SignalAndWaitUntilSignaled
+  // TargetThread::OtherLibraryCallback
+  // InvokeCallbackFunction (in other library)
+  // TargetThread::CallThroughOtherLibrary
+  EXPECT_EQ(3, other_library_frame - end_frame)
+      << "Stack:\n" << FormatSampleForDiagnosticOutput(sample, profile.modules);
+}
+
+// Checks that a stack that runs through a library that is unloading produces a
+// stack, and doesn't crash.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_UnloadingLibrary UnloadingLibrary
+#else
+#define MAYBE_UnloadingLibrary DISABLED_UnloadingLibrary
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_UnloadingLibrary) {
+  TestLibraryUnload(false);
+}
+
+// Checks that a stack that runs through a library that has been unloaded
+// produces a stack, and doesn't crash.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_UnloadedLibrary UnloadedLibrary
+#else
+#define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_UnloadedLibrary) {
+  TestLibraryUnload(true);
+}
+
 }  // namespace base
diff --git a/base/profiler/stack_sampling_profiler_win.cc b/base/profiler/stack_sampling_profiler_win.cc
deleted file mode 100644
index 1ccd134..0000000
--- a/base/profiler/stack_sampling_profiler_win.cc
+++ /dev/null
@@ -1,357 +0,0 @@
-// Copyright 2015 The Chromium Authors. 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/test_support_library.cc b/base/profiler/test_support_library.cc
new file mode 100644
index 0000000..035f8f7
--- /dev/null
+++ b/base/profiler/test_support_library.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Note: there is intentionally no header file associated with this library so
+// we don't risk implicitly demand loading it by accessing a symbol.
+
+#if defined(WIN32)
+#define BASE_PROFILER_TEST_SUPPORT_LIBRARY_EXPORT __declspec(dllexport)
+#else  // defined(WIN32)
+#define BASE_PROFILER_TEST_SUPPORT_LIBRARY_EXPORT __attribute__((visibility("default")))
+#endif
+
+namespace base {
+
+// Must be defined in an extern "C" block so we can look up the unmangled name.
+extern "C" {
+
+BASE_PROFILER_TEST_SUPPORT_LIBRARY_EXPORT void InvokeCallbackFunction(
+    void (*function)(void*),
+    void* arg) {
+  function(arg);
+  // Prevent tail call.
+  volatile int i = 0;
+  i = 1;
+}
+
+}  // extern "C"
+
+}  // namespace base
diff --git a/base/profiler/win32_stack_frame_unwinder.cc b/base/profiler/win32_stack_frame_unwinder.cc
new file mode 100644
index 0000000..74075cb
--- /dev/null
+++ b/base/profiler/win32_stack_frame_unwinder.cc
@@ -0,0 +1,292 @@
+// Copyright 2015 The Chromium Authors. All 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/win32_stack_frame_unwinder.h"
+
+#include <windows.h>
+#include <utility>
+
+#include "base/containers/hash_tables.h"
+#include "base/memory/singleton.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+// Win32UnwindFunctions -------------------------------------------------------
+
+const HMODULE ModuleHandleTraits::kNonNullModuleForTesting =
+    reinterpret_cast<HMODULE>(static_cast<uintptr_t>(-1));
+
+// static
+bool ModuleHandleTraits::CloseHandle(HMODULE handle) {
+  if (handle == kNonNullModuleForTesting)
+    return true;
+
+  return ::FreeLibrary(handle) != 0;
+}
+
+// static
+bool ModuleHandleTraits::IsHandleValid(HMODULE handle) {
+  return handle != nullptr;
+}
+
+// static
+HMODULE ModuleHandleTraits::NullHandle() {
+  return nullptr;
+}
+
+namespace {
+
+// Implements the UnwindFunctions interface for the corresponding Win32
+// functions.
+class Win32UnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions {
+public:
+  Win32UnwindFunctions();
+  ~Win32UnwindFunctions() override;
+
+  PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter,
+                                        PDWORD64 image_base) override;
+
+  void VirtualUnwind(DWORD64 image_base,
+                     DWORD64 program_counter,
+                     PRUNTIME_FUNCTION runtime_function,
+                     CONTEXT* context) override;
+
+  ScopedModuleHandle GetModuleForProgramCounter(
+      DWORD64 program_counter) override;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(Win32UnwindFunctions);
+};
+
+Win32UnwindFunctions::Win32UnwindFunctions() {}
+Win32UnwindFunctions::~Win32UnwindFunctions() {}
+
+PRUNTIME_FUNCTION Win32UnwindFunctions::LookupFunctionEntry(
+    DWORD64 program_counter,
+    PDWORD64 image_base) {
+#ifdef _WIN64
+  return RtlLookupFunctionEntry(program_counter, image_base, nullptr);
+#else
+  NOTREACHED();
+  return nullptr;
+#endif
+}
+
+void Win32UnwindFunctions::VirtualUnwind(DWORD64 image_base,
+                                         DWORD64 program_counter,
+                                         PRUNTIME_FUNCTION runtime_function,
+                                         CONTEXT* context) {
+#ifdef _WIN64
+  void* handler_data;
+  ULONG64 establisher_frame;
+  KNONVOLATILE_CONTEXT_POINTERS nvcontext = {};
+  RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, program_counter,
+                   runtime_function, context, &handler_data,
+                   &establisher_frame, &nvcontext);
+#else
+  NOTREACHED();
+#endif
+}
+
+ScopedModuleHandle Win32UnwindFunctions::GetModuleForProgramCounter(
+    DWORD64 program_counter) {
+  HMODULE module_handle = nullptr;
+  // GetModuleHandleEx() increments the module reference count, which is then
+  // managed and ultimately decremented by ScopedModuleHandle.
+  if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+                           reinterpret_cast<LPCTSTR>(program_counter),
+                           &module_handle)) {
+    const DWORD error = ::GetLastError();
+    DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error));
+  }
+  return ScopedModuleHandle(module_handle);
+}
+
+// LeafUnwindBlacklist --------------------------------------------------------
+
+// Records modules that are known to have functions that violate the Microsoft
+// x64 calling convention and would be dangerous to manually unwind if
+// encountered as the last frame on the call stack. Functions like these have
+// been observed in injected third party modules that either do not provide
+// function unwind information, or do not provide the required function prologue
+// and epilogue. The former case was observed in several AV products and the
+// latter in a WndProc function associated with Actual Window
+// Manager/aimemb64.dll. See https://crbug.com/476422.
+class LeafUnwindBlacklist {
+ public:
+  static LeafUnwindBlacklist* GetInstance();
+
+  // Returns true if |module| has been blacklisted.
+  bool IsBlacklisted(const void* module) const;
+
+  // Records |module| for blacklisting.
+  void BlacklistModule(const void* module);
+
+ private:
+  friend struct DefaultSingletonTraits<LeafUnwindBlacklist>;
+
+  LeafUnwindBlacklist();
+  ~LeafUnwindBlacklist();
+
+  // The set of modules known to have functions that violate the Microsoft x64
+  // calling convention.
+  base::hash_set<const void*> blacklisted_modules_;
+
+  DISALLOW_COPY_AND_ASSIGN(LeafUnwindBlacklist);
+};
+
+// static
+LeafUnwindBlacklist* LeafUnwindBlacklist::GetInstance() {
+  // Leaky for performance reasons.
+  return Singleton<LeafUnwindBlacklist,
+                   LeakySingletonTraits<LeafUnwindBlacklist>>::get();
+}
+
+bool LeafUnwindBlacklist::IsBlacklisted(const void* module) const {
+  return ContainsKey(blacklisted_modules_, module);
+}
+
+void LeafUnwindBlacklist::BlacklistModule(const void* module) {
+  CHECK(module);
+  blacklisted_modules_.insert(module);
+}
+
+LeafUnwindBlacklist::LeafUnwindBlacklist() {}
+LeafUnwindBlacklist::~LeafUnwindBlacklist() {}
+
+}  // namespace
+
+// Win32StackFrameUnwinder ----------------------------------------------------
+
+Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {}
+Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {}
+
+Win32StackFrameUnwinder::Win32StackFrameUnwinder()
+    : Win32StackFrameUnwinder(make_scoped_ptr(new Win32UnwindFunctions)) {
+}
+
+Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {}
+
+bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context,
+                                        ScopedModuleHandle* module) {
+#ifdef _WIN64
+  CHECK(!at_top_frame_ || unwind_info_present_for_all_frames_);
+
+  ScopedModuleHandle frame_module =
+      unwind_functions_->GetModuleForProgramCounter(context->Rip);
+  if (!frame_module.IsValid()) {
+    // There's no loaded module containing the instruction pointer. This can be
+    // due to executing code that is not in a module. In particular,
+    // runtime-generated code associated with third-party injected DLLs
+    // typically is not in a module. It can also be due to the the module having
+    // been unloaded since we recorded the stack.  In the latter case the
+    // function unwind information was part of the unloaded module, so it's not
+    // possible to unwind further.
+    //
+    // If a module was found, it's still theoretically possible for the detected
+    // module module to be different than the one that was loaded when the stack
+    // was copied (i.e. if the module was unloaded and a different module loaded
+    // in overlapping memory). This likely would cause a crash, but has not been
+    // observed in practice.
+    return false;
+  }
+
+  ULONG64 image_base;
+  // Try to look up unwind metadata for the current function.
+  PRUNTIME_FUNCTION runtime_function =
+      unwind_functions_->LookupFunctionEntry(context->Rip, &image_base);
+
+  if (runtime_function) {
+    unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function,
+                                     context);
+    at_top_frame_ = false;
+  } else {
+    // RtlLookupFunctionEntry didn't find unwind information. This could mean
+    // the code at the instruction pointer is in:
+    //
+    // 1. a true leaf function (i.e. a function that neither calls a function,
+    //    nor allocates any stack space itself) in which case the return
+    //    address is at RSP, or
+    //
+    // 2. a function that doesn't adhere to the Microsoft x64 calling
+    //    convention, either by not providing the required unwind information,
+    //    or by not having the prologue or epilogue required for unwinding;
+    //    this case has been observed in crash data in injected third party
+    //    DLLs.
+    //
+    // In valid code, case 1 can only occur (by definition) as the last frame
+    // on the stack. This happens in about 5% of observed stacks and can
+    // easily be unwound by popping RSP and using it as the next frame's
+    // instruction pointer.
+    //
+    // Case 2 can occur anywhere on the stack, and attempting to unwind the
+    // stack will result in treating whatever value happens to be on the stack
+    // at RSP as the next frame's instruction pointer. This is certainly wrong
+    // and very likely to lead to crashing by deferencing invalid pointers in
+    // the next RtlVirtualUnwind call.
+    //
+    // If we see case 2 at a location not the last frame, and all the previous
+    // frame had valid unwind information, then this is definitely bad code.
+    // We blacklist the module as untrustable for unwinding if we encounter a
+    // function in it that doesn't have unwind information.
+
+    if (at_top_frame_) {
+      at_top_frame_ = false;
+
+      // We are at the end of the stack. It's very likely that we're in case 1
+      // since the vast majority of code adheres to the Microsoft x64 calling
+      // convention. But there's a small chance we might be unlucky and be in
+      // case 2. If this module is known to have bad code according to the
+      // leaf unwind blacklist, stop here, otherwise manually unwind.
+      if (LeafUnwindBlacklist::GetInstance()->IsBlacklisted(
+              reinterpret_cast<const void*>(image_base))) {
+        return false;
+      }
+
+      context->Rip = context->Rsp;
+      context->Rsp += 8;
+      unwind_info_present_for_all_frames_ = false;
+    } else {
+      // We're not at the end of the stack. This frame is untrustworthy and we
+      // can't safely unwind from here.
+      if (!image_base) {
+        // A null image_base means that the the last unwind produced an invalid
+        // instruction pointer. This has been observed where unwind information
+        // was present for a function but was inconsistent with the actual
+        // function code, in particular in BoringSSL. See
+        // https://crbug.com/542919.
+      } else if (unwind_info_present_for_all_frames_) {
+        // Unwind information was present for all previous frames, so we can
+        // be confident this is case 2. Record the module to be blacklisted.
+        LeafUnwindBlacklist::GetInstance()->BlacklistModule(
+            reinterpret_cast<const void *>(image_base));
+      } else {
+        // We started off on a function without unwind information. It's very
+        // likely that all frames up to this point have been good, and this
+        // frame is case 2. But it's possible that the initial frame was case
+        // 2 but hadn't been blacklisted yet, and we've started to go off into
+        // the weeds. Since we can't be sure, just bail out without
+        // blacklisting the module; chances are we'll later encounter the same
+        // function on a stack with full unwind information.
+      }
+      return false;
+    }
+  }
+
+  module->Set(frame_module.Take());
+  return true;
+#else
+  NOTREACHED();
+  return false;
+#endif
+}
+
+Win32StackFrameUnwinder::Win32StackFrameUnwinder(
+    scoped_ptr<UnwindFunctions> unwind_functions)
+    : at_top_frame_(true),
+      unwind_info_present_for_all_frames_(true),
+      unwind_functions_(std::move(unwind_functions)) {}
+
+}  // namespace base
diff --git a/base/profiler/win32_stack_frame_unwinder.h b/base/profiler/win32_stack_frame_unwinder.h
new file mode 100644
index 0000000..18cd9d6
--- /dev/null
+++ b/base/profiler/win32_stack_frame_unwinder.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 BASE_PROFILER_WIN32_STACK_FRAME_UNWINDER_H_
+#define BASE_PROFILER_WIN32_STACK_FRAME_UNWINDER_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+#if !defined(_WIN64)
+// Allows code to compile for x86. Actual support for x86 will require either
+// refactoring these interfaces or separate architecture-specific interfaces.
+struct RUNTIME_FUNCTION {
+  DWORD BeginAddress;
+  DWORD EndAddress;
+};
+using PRUNTIME_FUNCTION = RUNTIME_FUNCTION*;
+#endif  // !defined(_WIN64)
+
+// Traits class to adapt GenericScopedHandle for HMODULES.
+class ModuleHandleTraits : public win::HandleTraits {
+ public:
+  using Handle = HMODULE;
+
+  static bool BASE_EXPORT CloseHandle(HMODULE handle);
+  static bool BASE_EXPORT IsHandleValid(HMODULE handle);
+  static HMODULE BASE_EXPORT NullHandle();
+
+  BASE_EXPORT static const HMODULE kNonNullModuleForTesting;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleHandleTraits);
+};
+
+// HMODULE is not really a handle, and has reference count semantics, so the
+// standard VerifierTraits does not apply.
+using ScopedModuleHandle =
+    win::GenericScopedHandle<ModuleHandleTraits, win::DummyVerifierTraits>;
+
+// Instances of this class are expected to be created and destroyed for each
+// stack unwinding. This class is not used while the target thread is suspended,
+// so may allocate from the default heap.
+class BASE_EXPORT Win32StackFrameUnwinder {
+ public:
+  // Interface for Win32 unwind-related functionality this class depends
+  // on. Provides a seam for testing.
+  class BASE_EXPORT UnwindFunctions {
+   public:
+    virtual ~UnwindFunctions();
+
+    virtual PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter,
+                                                  PDWORD64 image_base) = 0;
+    virtual void VirtualUnwind(DWORD64 image_base,
+                               DWORD64 program_counter,
+                               PRUNTIME_FUNCTION runtime_function,
+                               CONTEXT* context) = 0;
+
+    // Returns the module containing |program_counter|. Can return null if the
+    // module has been unloaded.
+    virtual ScopedModuleHandle GetModuleForProgramCounter(
+        DWORD64 program_counter) = 0;
+
+   protected:
+    UnwindFunctions();
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(UnwindFunctions);
+  };
+
+  Win32StackFrameUnwinder();
+  ~Win32StackFrameUnwinder();
+
+  // Attempts to unwind the frame represented by the stack and instruction
+  // pointers in |context|. If successful, updates |context| and provides the
+  // module associated with the frame in |module|.
+  bool TryUnwind(CONTEXT* context, ScopedModuleHandle* module);
+
+ private:
+  // This function is for internal and test purposes only.
+  Win32StackFrameUnwinder(scoped_ptr<UnwindFunctions> unwind_functions);
+  friend class Win32StackFrameUnwinderTest;
+
+  // State associated with each stack unwinding.
+  bool at_top_frame_;
+  bool unwind_info_present_for_all_frames_;
+
+  scoped_ptr<UnwindFunctions> unwind_functions_;
+
+  DISALLOW_COPY_AND_ASSIGN(Win32StackFrameUnwinder);
+};
+
+}  // namespace base
+
+#endif  // BASE_PROFILER_WIN32_STACK_FRAME_UNWINDER_H_
diff --git a/base/profiler/win32_stack_frame_unwinder_unittest.cc b/base/profiler/win32_stack_frame_unwinder_unittest.cc
new file mode 100644
index 0000000..fdf0858
--- /dev/null
+++ b/base/profiler/win32_stack_frame_unwinder_unittest.cc
@@ -0,0 +1,381 @@
+// Copyright 2015 The Chromium Authors. All 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/win32_stack_frame_unwinder.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions {
+ public:
+  TestUnwindFunctions();
+
+  PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter,
+                                        PDWORD64 image_base) override;
+  void VirtualUnwind(DWORD64 image_base,
+                     DWORD64 program_counter,
+                     PRUNTIME_FUNCTION runtime_function,
+                     CONTEXT* context) override;
+  ScopedModuleHandle GetModuleForProgramCounter(
+      DWORD64 program_counter) override;
+
+  // Instructs GetModuleForProgramCounter to return null on the next call.
+  void SetUnloadedModule();
+
+  // These functions set whether the next frame will have a RUNTIME_FUNCTION,
+  // and allow specification of a custom image_base.
+  void SetHasRuntimeFunction(CONTEXT* context);
+  void SetHasRuntimeFunction(DWORD64 image_base, CONTEXT* context);
+  void SetHasRuntimeFunction(DWORD64 image_base,
+                             const RUNTIME_FUNCTION& runtime_function,
+                             DWORD program_counter_offset,
+                             CONTEXT* context);
+  void SetNoRuntimeFunction(CONTEXT* context);
+  void SetNoRuntimeFunction(DWORD64 image_base, CONTEXT* context);
+
+ private:
+  enum RuntimeFunctionState { NO_RUNTIME_FUNCTION, HAS_RUNTIME_FUNCTION };
+
+  enum { kImageBaseIncrement = 1 << 20 };
+
+  // Sets whether the next frame should have a RUNTIME_FUNCTION, and allows
+  // specification of a custom image_base.
+  void SetNextFrameState(RuntimeFunctionState runtime_function_state,
+                         DWORD64 image_base,
+                         CONTEXT* context);
+
+  static RUNTIME_FUNCTION* const kInvalidRuntimeFunction;
+
+  bool module_is_loaded_;
+  DWORD64 expected_program_counter_;
+  DWORD64 custom_image_base_;
+  DWORD64 next_image_base_;
+  DWORD64 expected_image_base_;
+  RUNTIME_FUNCTION* next_runtime_function_;
+  std::vector<RUNTIME_FUNCTION> runtime_functions_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestUnwindFunctions);
+};
+
+RUNTIME_FUNCTION* const TestUnwindFunctions::kInvalidRuntimeFunction =
+    reinterpret_cast<RUNTIME_FUNCTION*>(static_cast<uintptr_t>(-1));
+
+TestUnwindFunctions::TestUnwindFunctions()
+    : module_is_loaded_(true),
+      expected_program_counter_(0),
+      custom_image_base_(0),
+      next_image_base_(kImageBaseIncrement),
+      expected_image_base_(0),
+      next_runtime_function_(kInvalidRuntimeFunction) {
+}
+
+PRUNTIME_FUNCTION TestUnwindFunctions::LookupFunctionEntry(
+    DWORD64 program_counter,
+    PDWORD64 image_base) {
+  EXPECT_EQ(expected_program_counter_, program_counter);
+  if (custom_image_base_) {
+    *image_base = expected_image_base_ = custom_image_base_;
+    custom_image_base_ = 0;
+  } else {
+    *image_base = expected_image_base_ = next_image_base_;
+    next_image_base_ += kImageBaseIncrement;
+  }
+  RUNTIME_FUNCTION* return_value = next_runtime_function_;
+  next_runtime_function_ = kInvalidRuntimeFunction;
+  return return_value;
+}
+
+void TestUnwindFunctions::VirtualUnwind(DWORD64 image_base,
+                                        DWORD64 program_counter,
+                                        PRUNTIME_FUNCTION runtime_function,
+                                        CONTEXT* context) {
+  ASSERT_NE(kInvalidRuntimeFunction, runtime_function)
+      << "expected call to SetHasRuntimeFunction() or SetNoRuntimeFunction() "
+      << "before invoking TryUnwind()";
+  EXPECT_EQ(expected_image_base_, image_base);
+  expected_image_base_ = 0;
+  EXPECT_EQ(expected_program_counter_, program_counter);
+  expected_program_counter_ = 0;
+  // This function should only be called when LookupFunctionEntry returns
+  // a RUNTIME_FUNCTION.
+  EXPECT_EQ(&runtime_functions_.back(), runtime_function);
+}
+
+ScopedModuleHandle TestUnwindFunctions::GetModuleForProgramCounter(
+    DWORD64 program_counter) {
+  bool return_non_null_value = module_is_loaded_;
+  module_is_loaded_ = true;
+  return ScopedModuleHandle(return_non_null_value ?
+                            ModuleHandleTraits::kNonNullModuleForTesting :
+                            nullptr);
+}
+
+void TestUnwindFunctions::SetUnloadedModule() {
+  module_is_loaded_ = false;
+}
+
+void TestUnwindFunctions::SetHasRuntimeFunction(CONTEXT* context) {
+  SetNextFrameState(HAS_RUNTIME_FUNCTION, 0, context);
+}
+
+void TestUnwindFunctions::SetHasRuntimeFunction(DWORD64 image_base,
+                                                CONTEXT* context) {
+  SetNextFrameState(HAS_RUNTIME_FUNCTION, image_base, context);
+}
+
+void TestUnwindFunctions::SetHasRuntimeFunction(
+    DWORD64 image_base,
+    const RUNTIME_FUNCTION& runtime_function,
+    DWORD program_counter_offset,
+    CONTEXT* context) {
+  custom_image_base_ = image_base;
+  runtime_functions_.push_back(runtime_function);
+  next_runtime_function_ = &runtime_functions_.back();
+  expected_program_counter_ = context->Rip =
+      image_base + program_counter_offset;
+}
+
+void TestUnwindFunctions::SetNoRuntimeFunction(CONTEXT* context) {
+  SetNextFrameState(NO_RUNTIME_FUNCTION, 0, context);
+}
+
+void TestUnwindFunctions::SetNoRuntimeFunction(DWORD64 image_base,
+                                               CONTEXT* context) {
+  SetNextFrameState(NO_RUNTIME_FUNCTION, image_base, context);
+}
+
+
+void TestUnwindFunctions::SetNextFrameState(
+    RuntimeFunctionState runtime_function_state,
+    DWORD64 image_base,
+    CONTEXT* context) {
+  if (image_base)
+    custom_image_base_ = image_base;
+
+  if (runtime_function_state == HAS_RUNTIME_FUNCTION) {
+    RUNTIME_FUNCTION runtime_function = {};
+    runtime_function.BeginAddress = 16;
+    runtime_function.EndAddress = runtime_function.BeginAddress + 256;
+    runtime_functions_.push_back(runtime_function);
+    next_runtime_function_ = &runtime_functions_.back();
+
+    DWORD64 image_base = custom_image_base_ ? custom_image_base_ :
+        next_image_base_;
+    expected_program_counter_ = context->Rip =
+        image_base + runtime_function.BeginAddress + 8;
+  } else {
+    expected_program_counter_ = context->Rip = 100;
+    next_runtime_function_ = nullptr;
+  }
+}
+
+}  // namespace
+
+class Win32StackFrameUnwinderTest : public testing::Test {
+ protected:
+  Win32StackFrameUnwinderTest() {}
+
+  // This exists so that Win32StackFrameUnwinder's constructor can be private
+  // with a single friend declaration of this test fixture.
+  scoped_ptr<Win32StackFrameUnwinder> CreateUnwinder();
+
+  // Weak pointer to the unwind functions used by last created unwinder.
+  TestUnwindFunctions* unwind_functions_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Win32StackFrameUnwinderTest);
+};
+
+scoped_ptr<Win32StackFrameUnwinder>
+Win32StackFrameUnwinderTest::CreateUnwinder() {
+  scoped_ptr<TestUnwindFunctions> unwind_functions(new TestUnwindFunctions);
+  unwind_functions_ = unwind_functions.get();
+  return make_scoped_ptr(
+      new Win32StackFrameUnwinder(std::move(unwind_functions)));
+}
+
+// Checks the case where all frames have unwind information.
+TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) {
+  scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+  CONTEXT context = {0};
+  ScopedModuleHandle module;
+
+  unwind_functions_->SetHasRuntimeFunction(&context);
+  EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+  EXPECT_TRUE(module.IsValid());
+
+  unwind_functions_->SetHasRuntimeFunction(&context);
+  module.Set(nullptr);
+  EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+  EXPECT_TRUE(module.IsValid());
+
+  unwind_functions_->SetHasRuntimeFunction(&context);
+  module.Set(nullptr);
+  EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+  EXPECT_TRUE(module.IsValid());
+}
+
+// Checks that an instruction pointer in an unloaded module fails to unwind.
+TEST_F(Win32StackFrameUnwinderTest, UnloadedModule) {
+  scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+  CONTEXT context = {0};
+  ScopedModuleHandle module;
+
+  unwind_functions_->SetUnloadedModule();
+  EXPECT_FALSE(unwinder->TryUnwind(&context, &module));
+}
+
+// Checks that the CONTEXT's stack pointer gets popped when the top frame has no
+// unwind information.
+TEST_F(Win32StackFrameUnwinderTest, FrameAtTopWithoutUnwindInfo) {
+  scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+  CONTEXT context = {0};
+  ScopedModuleHandle module;
+  const DWORD64 original_rsp = 128;
+  context.Rsp = original_rsp;
+
+  unwind_functions_->SetNoRuntimeFunction(&context);
+  EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+  EXPECT_EQ(original_rsp, context.Rip);
+  EXPECT_EQ(original_rsp + 8, context.Rsp);
+  EXPECT_TRUE(module.IsValid());
+
+  unwind_functions_->SetHasRuntimeFunction(&context);
+  module.Set(nullptr);
+  EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+  EXPECT_TRUE(module.IsValid());
+
+  unwind_functions_->SetHasRuntimeFunction(&context);
+  module.Set(nullptr);
+  EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+  EXPECT_TRUE(module.IsValid());
+}
+
+// Checks that a frame below the top of the stack with missing unwind info
+// results in blacklisting the module.
+TEST_F(Win32StackFrameUnwinderTest, BlacklistedModule) {
+  const DWORD64 image_base_for_module_with_bad_function = 1024;
+  {
+    // First stack, with a bad function below the top of the stack.
+    scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+    CONTEXT context = {0};
+    ScopedModuleHandle module;
+    unwind_functions_->SetHasRuntimeFunction(&context);
+    EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+    EXPECT_TRUE(module.IsValid());
+
+    unwind_functions_->SetNoRuntimeFunction(
+        image_base_for_module_with_bad_function,
+        &context);
+    EXPECT_FALSE(unwinder->TryUnwind(&context, &module));
+  }
+
+  {
+    // Second stack; check that a function at the top of the stack without
+    // unwind info from the previously-seen module is blacklisted.
+    scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+    CONTEXT context = {0};
+    ScopedModuleHandle module;
+    unwind_functions_->SetNoRuntimeFunction(
+        image_base_for_module_with_bad_function,
+        &context);
+    EXPECT_FALSE(unwinder->TryUnwind(&context, &module));
+  }
+
+  {
+    // Third stack; check that a function at the top of the stack *with* unwind
+    // info from the previously-seen module is not blacklisted. Then check that
+    // functions below the top of the stack with unwind info are not
+    // blacklisted, regardless of whether they are in the previously-seen
+    // module.
+    scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+    CONTEXT context = {0};
+    ScopedModuleHandle module;
+    unwind_functions_->SetHasRuntimeFunction(
+        image_base_for_module_with_bad_function,
+        &context);
+    EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+    EXPECT_TRUE(module.IsValid());
+
+    unwind_functions_->SetHasRuntimeFunction(&context);
+    module.Set(nullptr);
+    EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+    EXPECT_TRUE(module.IsValid());
+
+    unwind_functions_->SetHasRuntimeFunction(
+        image_base_for_module_with_bad_function,
+        &context);
+    module.Set(nullptr);
+    EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+    EXPECT_TRUE(module.IsValid());
+  }
+
+  {
+    // Fourth stack; check that a function at the top of the stack without
+    // unwind info and not from the previously-seen module is not
+    // blacklisted. Then check that functions below the top of the stack with
+    // unwind info are not blacklisted, regardless of whether they are in the
+    // previously-seen module.
+    scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+    CONTEXT context = {0};
+    ScopedModuleHandle module;
+    unwind_functions_->SetNoRuntimeFunction(&context);
+    EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+    EXPECT_TRUE(module.IsValid());
+
+    unwind_functions_->SetHasRuntimeFunction(&context);
+    module.Set(nullptr);
+    EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+    EXPECT_TRUE(module.IsValid());
+
+    unwind_functions_->SetHasRuntimeFunction(
+        image_base_for_module_with_bad_function,
+        &context);
+    module.Set(nullptr);
+    EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+    EXPECT_TRUE(module.IsValid());
+  }
+}
+
+// Checks that a frame below the top of the stack with missing unwind info does
+// not result in blacklisting the module if the first frame also was missing
+// unwind info. This ensures we don't blacklist an innocent module because the
+// first frame was bad but we didn't know it at the time.
+TEST_F(Win32StackFrameUnwinderTest, ModuleFromQuestionableFrameNotBlacklisted) {
+  const DWORD64 image_base_for_questionable_module = 2048;
+  {
+    // First stack, with both the first and second frames missing unwind info.
+    scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+    CONTEXT context = {0};
+    ScopedModuleHandle module;
+    unwind_functions_->SetNoRuntimeFunction(&context);
+    EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+    EXPECT_TRUE(module.IsValid());
+
+    unwind_functions_->SetNoRuntimeFunction(image_base_for_questionable_module,
+                                            &context);
+    EXPECT_FALSE(unwinder->TryUnwind(&context, &module));
+  }
+
+  {
+    // Second stack; check that the questionable module was not blacklisted.
+    scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+    CONTEXT context = {0};
+    ScopedModuleHandle module;
+    unwind_functions_->SetNoRuntimeFunction(image_base_for_questionable_module,
+                                            &context);
+    EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+    EXPECT_TRUE(module.IsValid());
+  }
+}
+
+}  // namespace base
diff --git a/base/rand_util.cc b/base/rand_util.cc
index 1525b91..1a3b79e 100644
--- a/base/rand_util.cc
+++ b/base/rand_util.cc
@@ -5,11 +5,11 @@
 #include "base/rand_util.h"
 
 #include <math.h>
+#include <stdint.h>
 
 #include <algorithm>
 #include <limits>
 
-#include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 
@@ -18,8 +18,11 @@
 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));
+  uint64_t range = static_cast<uint64_t>(max) - min + 1;
+  // |range| is at most UINT_MAX + 1, so the result of RandGenerator(range)
+  // is at most UINT_MAX.  Hence it's safe to cast it from uint64_t to int64_t.
+  int result =
+      static_cast<int>(min + static_cast<int64_t>(base::RandGenerator(range)));
   DCHECK_GE(result, min);
   DCHECK_LE(result, max);
   return result;
@@ -29,31 +32,32 @@
   return BitsToOpenEndedUnitInterval(base::RandUint64());
 }
 
-double BitsToOpenEndedUnitInterval(uint64 bits) {
+double BitsToOpenEndedUnitInterval(uint64_t bits) {
   // We try to get maximum precision by masking out as many bits as will fit
   // in the target type's mantissa, and raising it to an appropriate power to
   // produce output in the range [0, 1).  For IEEE 754 doubles, the mantissa
   // is expected to accommodate 53 bits.
 
-  COMPILE_ASSERT(std::numeric_limits<double>::radix == 2, otherwise_use_scalbn);
+  static_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);
+  uint64_t random_bits = bits & ((UINT64_C(1) << kBits) - 1);
   double result = ldexp(static_cast<double>(random_bits), -1 * kBits);
   DCHECK_GE(result, 0.0);
   DCHECK_LT(result, 1.0);
   return result;
 }
 
-uint64 RandGenerator(uint64 range) {
+uint64_t RandGenerator(uint64_t range) {
   DCHECK_GT(range, 0u);
   // We must discard random results above this number, as they would
   // make the random generator non-uniform (consider e.g. if
   // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice
   // as likely as a result of 3 or 4).
-  uint64 max_acceptable_value =
-      (std::numeric_limits<uint64>::max() / range) * range - 1;
+  uint64_t max_acceptable_value =
+      (std::numeric_limits<uint64_t>::max() / range) * range - 1;
 
-  uint64 value;
+  uint64_t value;
   do {
     value = base::RandUint64();
   } while (value > max_acceptable_value);
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc
index 90690ec..689b8ad 100644
--- a/base/rand_util_unittest.cc
+++ b/base/rand_util_unittest.cc
@@ -19,10 +19,16 @@
 
 }  // namespace
 
-TEST(RandUtilTest, SameMinAndMax) {
+TEST(RandUtilTest, RandInt) {
   EXPECT_EQ(base::RandInt(0, 0), 0);
   EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin);
   EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax);
+
+  // Check that the DCHECKS in RandInt() don't fire due to internal overflow.
+  // There was a 50% chance of that happening, so calling it 40 times means
+  // the chances of this passing by accident are tiny (9e-13).
+  for (int i = 0; i < 40; ++i)
+    base::RandInt(kIntMin, kIntMax);
 }
 
 TEST(RandUtilTest, RandDouble) {
diff --git a/base/run_loop.h b/base/run_loop.h
index 0024108..9ff8d39 100644
--- a/base/run_loop.h
+++ b/base/run_loop.h
@@ -38,8 +38,8 @@
 
   // 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.
+  // stop the MessageLoop asynchronously. MessageLoop::QuitWhenIdle and QuitNow
+  // will also trigger a return from Run, but those are deprecated.
   void Run();
 
   // Run the current MessageLoop until it doesn't find any tasks or messages in
diff --git a/base/scoped_generic_unittest.cc b/base/scoped_generic_unittest.cc
index b28e154..5a6abfb 100644
--- a/base/scoped_generic_unittest.cc
+++ b/base/scoped_generic_unittest.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/scoped_generic.h"
+
+#include <utility>
 #include <vector>
 
-#include "base/scoped_generic.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -85,10 +87,10 @@
   EXPECT_EQ(kSecond, values_freed[1]);
   values_freed.clear();
 
-  // Pass constructor.
+  // Move constructor.
   {
     ScopedInt a(kFirst, traits);
-    ScopedInt b(a.Pass());
+    ScopedInt b(std::move(a));
     EXPECT_TRUE(values_freed.empty());  // Nothing should be freed.
     ASSERT_EQ(IntTraits::InvalidValue(), a.get());
     ASSERT_EQ(kFirst, b.get());
@@ -98,11 +100,11 @@
   ASSERT_EQ(kFirst, values_freed[0]);
   values_freed.clear();
 
-  // Pass assign.
+  // Move assign.
   {
     ScopedInt a(kFirst, traits);
     ScopedInt b(kSecond, traits);
-    b = a.Pass();
+    b = std::move(a);
     ASSERT_EQ(1u, values_freed.size());
     EXPECT_EQ(kSecond, values_freed[0]);
     ASSERT_EQ(IntTraits::InvalidValue(), a.get());
diff --git a/base/scoped_native_library.h b/base/scoped_native_library.h
index c0e93f3..bfe5566 100644
--- a/base/scoped_native_library.h
+++ b/base/scoped_native_library.h
@@ -31,6 +31,8 @@
   // Returns true if there's a valid library loaded.
   bool is_valid() const { return !!library_; }
 
+  NativeLibrary get() const { return library_; }
+
   void* GetFunctionPointer(const char* function_name) const;
 
   // Takes ownership of the given library handle. Any existing handle will
diff --git a/base/scoped_native_library_unittest.cc b/base/scoped_native_library_unittest.cc
index 035faa0..c7e4489 100644
--- a/base/scoped_native_library_unittest.cc
+++ b/base/scoped_native_library_unittest.cc
@@ -28,6 +28,8 @@
     FilePath path(GetNativeLibraryName(L"ddraw"));
     native_library = LoadNativeLibrary(path, NULL);
     ScopedNativeLibrary library(native_library);
+    EXPECT_TRUE(library.is_valid());
+    EXPECT_EQ(native_library, library.get());
     FARPROC test_function =
         reinterpret_cast<FARPROC>(library.GetFunctionPointer(kFunctionName));
     EXPECT_EQ(0, IsBadCodePtr(test_function));
diff --git a/base/security_unittest.cc b/base/security_unittest.cc
index 07ba6f5..cd387fb 100644
--- a/base/security_unittest.cc
+++ b/base/security_unittest.cc
@@ -23,47 +23,11 @@
 #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
@@ -92,144 +56,16 @@
 #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;
-
+#if defined(OS_LINUX) && defined(__x86_64__)
 // 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
@@ -249,7 +85,7 @@
   }
 }
 
-#if defined(OS_IOS) || defined(OS_WIN) || defined(THREAD_SANITIZER) || defined(OS_MACOSX)
+#if defined(OS_IOS) || defined(OS_WIN) || defined(OS_MACOSX)
 #define MAYBE_NewOverflow DISABLED_NewOverflow
 #else
 #define MAYBE_NewOverflow NewOverflow
@@ -287,34 +123,6 @@
 #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) {
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc
index 0aa0f9c..f0eda25 100644
--- a/base/sequence_checker_unittest.cc
+++ b/base/sequence_checker_unittest.cc
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/sequence_checker.h"
+
+#include <utility>
+
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -9,7 +13,6 @@
 #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"
@@ -130,7 +133,7 @@
       new SequenceCheckedObject);
 
   // Verify the destructor doesn't assert when called on a different thread.
-  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  PostDeleteToOtherThread(std::move(sequence_checked_object));
   other_thread()->Stop();
 }
 
@@ -157,7 +160,7 @@
   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
   pool()->FlushForTesting();
 
-  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  PostDeleteToOtherThread(std::move(sequence_checked_object));
   other_thread()->Stop();
 }
 
@@ -175,7 +178,7 @@
   PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
   pool()->FlushForTesting();
 
-  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  PostDeleteToOtherThread(std::move(sequence_checked_object));
   other_thread()->Stop();
 }
 
@@ -245,7 +248,7 @@
   PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
   pool()->FlushForTesting();
 
-  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  PostDeleteToOtherThread(std::move(sequence_checked_object));
   other_thread()->Stop();
 }
 
diff --git a/base/stl_util.h b/base/stl_util.h
index e937d2f..12e226a 100644
--- a/base/stl_util.h
+++ b/base/stl_util.h
@@ -98,19 +98,6 @@
   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.
diff --git a/base/strings/pattern.cc b/base/strings/pattern.cc
new file mode 100644
index 0000000..af30aab
--- /dev/null
+++ b/base/strings/pattern.cc
@@ -0,0 +1,169 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/pattern.h"
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+namespace {
+
+static bool IsWildcard(base_icu::UChar32 character) {
+  return character == '*' || character == '?';
+}
+
+// Move the strings pointers to the point where they start to differ.
+template <typename CHAR, typename NEXT>
+static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
+                         const CHAR** string, const CHAR* string_end,
+                         NEXT next) {
+  const CHAR* escape = NULL;
+  while (*pattern != pattern_end && *string != string_end) {
+    if (!escape && IsWildcard(**pattern)) {
+      // We don't want to match wildcard here, except if it's escaped.
+      return;
+    }
+
+    // Check if the escapement char is found. If so, skip it and move to the
+    // next character.
+    if (!escape && **pattern == '\\') {
+      escape = *pattern;
+      next(pattern, pattern_end);
+      continue;
+    }
+
+    // Check if the chars match, if so, increment the ptrs.
+    const CHAR* pattern_next = *pattern;
+    const CHAR* string_next = *string;
+    base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
+    if (pattern_char == next(&string_next, string_end) &&
+        pattern_char != CBU_SENTINEL) {
+      *pattern = pattern_next;
+      *string = string_next;
+    } else {
+      // Uh oh, it did not match, we are done. If the last char was an
+      // escapement, that means that it was an error to advance the ptr here,
+      // let's put it back where it was. This also mean that the MatchPattern
+      // function will return false because if we can't match an escape char
+      // here, then no one will.
+      if (escape) {
+        *pattern = escape;
+      }
+      return;
+    }
+
+    escape = NULL;
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
+  while (*pattern != end) {
+    if (!IsWildcard(**pattern))
+      return;
+    next(pattern, end);
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
+                          const CHAR* pattern, const CHAR* pattern_end,
+                          int depth,
+                          NEXT next) {
+  const int kMaxDepth = 16;
+  if (depth > kMaxDepth)
+    return false;
+
+  // Eat all the matching chars.
+  EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
+
+  // If the string is empty, then the pattern must be empty too, or contains
+  // only wildcards.
+  if (eval == eval_end) {
+    EatWildcard(&pattern, pattern_end, next);
+    return pattern == pattern_end;
+  }
+
+  // Pattern is empty but not string, this is not a match.
+  if (pattern == pattern_end)
+    return false;
+
+  // If this is a question mark, then we need to compare the rest with
+  // the current string or the string with one character eaten.
+  const CHAR* next_pattern = pattern;
+  next(&next_pattern, pattern_end);
+  if (pattern[0] == '?') {
+    if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+                      depth + 1, next))
+      return true;
+    const CHAR* next_eval = eval;
+    next(&next_eval, eval_end);
+    if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
+                      depth + 1, next))
+      return true;
+  }
+
+  // This is a *, try to match all the possible substrings with the remainder
+  // of the pattern.
+  if (pattern[0] == '*') {
+    // Collapse duplicate wild cards (********** into *) so that the
+    // method does not recurse unnecessarily. http://crbug.com/52839
+    EatWildcard(&next_pattern, pattern_end, next);
+
+    while (eval != eval_end) {
+      if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+                        depth + 1, next))
+        return true;
+      eval++;
+    }
+
+    // We reached the end of the string, let see if the pattern contains only
+    // wildcards.
+    if (eval == eval_end) {
+      EatWildcard(&pattern, pattern_end, next);
+      if (pattern != pattern_end)
+        return false;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+struct NextCharUTF8 {
+  base_icu::UChar32 operator()(const char** p, const char* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU8_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+struct NextCharUTF16 {
+  base_icu::UChar32 operator()(const char16** p, const char16* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU16_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+}  // namespace
+
+bool MatchPattern(const StringPiece& eval, const StringPiece& pattern) {
+  return MatchPatternT(eval.data(), eval.data() + eval.size(),
+                       pattern.data(), pattern.data() + pattern.size(),
+                       0, NextCharUTF8());
+}
+
+bool MatchPattern(const StringPiece16& eval, const StringPiece16& pattern) {
+  return MatchPatternT(eval.data(), eval.data() + eval.size(),
+                       pattern.data(), pattern.data() + pattern.size(),
+                       0, NextCharUTF16());
+}
+
+}  // namespace base
diff --git a/base/strings/pattern.h b/base/strings/pattern.h
new file mode 100644
index 0000000..b698207
--- /dev/null
+++ b/base/strings/pattern.h
@@ -0,0 +1,26 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_PATTERN_H_
+#define BASE_STRINGS_PATTERN_H_
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Returns true if the string passed in matches the pattern. The pattern
+// string can contain wildcards like * and ?
+//
+// The backslash character (\) is an escape character for * and ?
+// We limit the patterns to having a max of 16 * or ? characters.
+// ? matches 0 or 1 character, while * matches 0 or more characters.
+BASE_EXPORT bool MatchPattern(const StringPiece& string,
+                              const StringPiece& pattern);
+BASE_EXPORT bool MatchPattern(const StringPiece16& string,
+                              const StringPiece16& pattern);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_PATTERN_H_
diff --git a/base/strings/pattern_unittest.cc b/base/strings/pattern_unittest.cc
new file mode 100644
index 0000000..9e82b3c
--- /dev/null
+++ b/base/strings/pattern_unittest.cc
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/pattern.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(StringUtilTest, MatchPatternTest) {
+  EXPECT_TRUE(MatchPattern("www.google.com", "*.com"));
+  EXPECT_TRUE(MatchPattern("www.google.com", "*"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "www*.g*.org"));
+  EXPECT_TRUE(MatchPattern("Hello", "H?l?o"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "http://*)"));
+  EXPECT_FALSE(MatchPattern("www.msn.com", "*.COM"));
+  EXPECT_TRUE(MatchPattern("Hello*1234", "He??o\\*1*"));
+  EXPECT_FALSE(MatchPattern("", "*.*"));
+  EXPECT_TRUE(MatchPattern("", "*"));
+  EXPECT_TRUE(MatchPattern("", "?"));
+  EXPECT_TRUE(MatchPattern("", ""));
+  EXPECT_FALSE(MatchPattern("Hello", ""));
+  EXPECT_TRUE(MatchPattern("Hello*", "Hello*"));
+  // Stop after a certain recursion depth.
+  EXPECT_FALSE(MatchPattern("123456789012345678", "?????????????????*"));
+
+  // Test UTF8 matching.
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0"));
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0.", "heart: ?."));
+  EXPECT_TRUE(MatchPattern("hearts: \xe2\x99\xa0\xe2\x99\xa0", "*"));
+  // Invalid sequences should be handled as a single invalid character.
+  EXPECT_TRUE(MatchPattern("invalid: \xef\xbf\xbe", "invalid: ?"));
+  // If the pattern has invalid characters, it shouldn't match anything.
+  EXPECT_FALSE(MatchPattern("\xf4\x90\x80\x80", "\xf4\x90\x80\x80"));
+
+  // Test UTF16 character matching.
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("www.google.com"),
+                           UTF8ToUTF16("*.com")));
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello*1234"),
+                           UTF8ToUTF16("He??o\\*1*")));
+
+  // This test verifies that consecutive wild cards are collapsed into 1
+  // wildcard (when this doesn't occur, MatchPattern reaches it's maximum
+  // recursion depth).
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello"),
+                           UTF8ToUTF16("He********************************o")));
+}
+
+}  // namespace base
diff --git a/base/strings/safe_sprintf.cc b/base/strings/safe_sprintf.cc
index b1fcf45..9719abd 100644
--- a/base/strings/safe_sprintf.cc
+++ b/base/strings/safe_sprintf.cc
@@ -4,6 +4,9 @@
 
 #include "base/strings/safe_sprintf.h"
 
+#include <errno.h>
+#include <string.h>
+
 #include <limits>
 
 #if !defined(NDEBUG)
@@ -69,7 +72,7 @@
 #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
+// use careful casting and shifting. We later use a static_assert to
 // verify that this worked correctly.
 namespace {
 const size_t kSSizeMax = kSSizeMaxConst;
@@ -107,18 +110,13 @@
       : 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);
+// MSVS2013's standard library doesn't mark max() as constexpr yet. cl.exe
+// supports static_cast but doesn't really implement constexpr yet so it doesn't
+// complain, but clang does.
+#if __cplusplus >= 201103 && !(defined(__clang__) && defined(OS_WIN))
+    static_assert(kSSizeMaxConst ==
+                      static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
+                  "kSSizeMaxConst should be the max value of an ssize_t");
 #endif
     DEBUG_CHECK(size > 0);
     DEBUG_CHECK(size <= kSSizeMax);
diff --git a/base/strings/string16.h b/base/strings/string16.h
index 1a01a96..ba4ffe7 100644
--- a/base/strings/string16.h
+++ b/base/strings/string16.h
@@ -64,7 +64,8 @@
 
   // 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);
+  static_assert(sizeof(int_type) > sizeof(char_type),
+                "int must be larger than 16 bits wide");
 
   typedef std::streamoff off_type;
   typedef mbstate_t state_type;
diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc
index 642d24e..0f4f381 100644
--- a/base/strings/string_number_conversions.cc
+++ b/base/strings/string_number_conversions.cc
@@ -12,6 +12,8 @@
 #include <limits>
 
 #include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/numerics/safe_math.h"
 #include "base/scoped_clear_errno.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/third_party/dmg_fp/dmg_fp.h"
@@ -20,77 +22,37 @@
 
 namespace {
 
-template <typename STR, typename INT, typename UINT, bool NEG>
+template <typename STR, typename INT>
 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;
+    const size_t kOutputBufSize =
+        3 * sizeof(INT) + std::numeric_limits<INT>::is_signed;
 
-    // Allocate the whole string right away, we will right back to front, and
+    // Create the string in a temporary buffer, write it back to front, and
     // then return the substr of what we ended up using.
-    STR outbuf(kOutputBufSize, 0);
+    using CHR = typename STR::value_type;
+    CHR outbuf[kOutputBufSize];
 
-    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);
+    // The ValueOrDie call below can never fail, because UnsignedAbs is valid
+    // for all valid inputs.
+    auto res = CheckedNumeric<INT>(value).UnsignedAbs().ValueOrDie();
 
-    typename STR::iterator it(outbuf.end());
+    CHR* end = outbuf + kOutputBufSize;
+    CHR* i = end;
     do {
-      --it;
-      DCHECK(it != outbuf.begin());
-      *it = static_cast<typename STR::value_type>((res % 10) + '0');
+      --i;
+      DCHECK(i != outbuf);
+      *i = static_cast<CHR>((res % 10) + '0');
       res /= 10;
     } while (res != 0);
-    if (is_neg) {
-      --it;
-      DCHECK(it != outbuf.begin());
-      *it = static_cast<typename STR::value_type>('-');
+    if (IsValueNegative(value)) {
+      --i;
+      DCHECK(i != outbuf);
+      *i = static_cast<CHR>('-');
     }
-    return STR(it, outbuf.end());
+    return STR(i, end);
   }
 };
 
@@ -131,10 +93,10 @@
   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.
+// There is an IsUnicodeWhitespace for wchars defined in string_util.h, but it
+// is locale independent, whereas the functions we are replacing were
+// locale-dependent. TBD what is desired, but for the moment let's not
+// introduce a change in behaviour.
 template<typename CHAR> class WhitespaceHelper {
 };
 
@@ -368,47 +330,43 @@
 }  // namespace
 
 std::string IntToString(int value) {
-  return IntToStringT<std::string, int, unsigned int, true>::
-      IntToString(value);
+  return IntToStringT<std::string, int>::IntToString(value);
 }
 
 string16 IntToString16(int value) {
-  return IntToStringT<string16, int, unsigned int, true>::
-      IntToString(value);
+  return IntToStringT<string16, int>::IntToString(value);
 }
 
 std::string UintToString(unsigned int value) {
-  return IntToStringT<std::string, unsigned int, unsigned int, false>::
-      IntToString(value);
+  return IntToStringT<std::string, unsigned int>::IntToString(value);
 }
 
 string16 UintToString16(unsigned int value) {
-  return IntToStringT<string16, unsigned int, unsigned int, false>::
-      IntToString(value);
+  return IntToStringT<string16, unsigned int>::IntToString(value);
 }
 
 std::string Int64ToString(int64 value) {
-  return IntToStringT<std::string, int64, uint64, true>::IntToString(value);
+  return IntToStringT<std::string, int64>::IntToString(value);
 }
 
 string16 Int64ToString16(int64 value) {
-  return IntToStringT<string16, int64, uint64, true>::IntToString(value);
+  return IntToStringT<string16, int64>::IntToString(value);
 }
 
 std::string Uint64ToString(uint64 value) {
-  return IntToStringT<std::string, uint64, uint64, false>::IntToString(value);
+  return IntToStringT<std::string, uint64>::IntToString(value);
 }
 
 string16 Uint64ToString16(uint64 value) {
-  return IntToStringT<string16, uint64, uint64, false>::IntToString(value);
+  return IntToStringT<string16, uint64>::IntToString(value);
 }
 
 std::string SizeTToString(size_t value) {
-  return IntToStringT<std::string, size_t, size_t, false>::IntToString(value);
+  return IntToStringT<std::string, size_t>::IntToString(value);
 }
 
 string16 SizeTToString16(size_t value) {
-  return IntToStringT<string16, size_t, size_t, false>::IntToString(value);
+  return IntToStringT<string16, size_t>::IntToString(value);
 }
 
 std::string DoubleToString(double value) {
diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h
index 050e627..cf1c3b4 100644
--- a/base/strings/string_number_conversions.h
+++ b/base/strings/string_number_conversions.h
@@ -64,6 +64,8 @@
 //  - No characters parseable as a number at the beginning of the string.
 //    |*output| will be set to 0.
 //  - Empty string.  |*output| will be set to 0.
+// WARNING: Will write to |output| even when returning false.
+//          Read the comments above carefully.
 BASE_EXPORT bool StringToInt(const StringPiece& input, int* output);
 BASE_EXPORT bool StringToInt(const StringPiece16& input, int* output);
 
@@ -81,10 +83,12 @@
 
 // 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
+// numbers in hexadecimal, and strings representing non-finite values (such as
 // NaN and inf) is undefined.  Otherwise, these behave the same as the integral
 // variants.  This expects the input string to NOT be specific to the locale.
 // If your input is locale specific, use ICU to read the number.
+// WARNING: Will write to |output| even when returning false.
+//          Read the comments here and above StringToInt() carefully.
 BASE_EXPORT bool StringToDouble(const std::string& input, double* output);
 
 // Hex encoding ----------------------------------------------------------------
diff --git a/base/strings/string_number_conversions_unittest.cc b/base/strings/string_number_conversions_unittest.cc
index 4787614..0bc72f1 100644
--- a/base/strings/string_number_conversions_unittest.cc
+++ b/base/strings/string_number_conversions_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/strings/string_number_conversions.h"
+
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -10,7 +12,6 @@
 #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"
@@ -237,10 +238,10 @@
     {"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},
+    {"-2147483649", INT64_C(-2147483649), true},
+    {"-99999999999", INT64_C(-99999999999), true},
+    {"2147483648", INT64_C(2147483648), true},
+    {"99999999999", INT64_C(99999999999), true},
     {"9223372036854775807", kint64max, true},
     {"-9223372036854775808", kint64min, true},
     {"09", 9, true},
@@ -304,8 +305,8 @@
     {"2147483647", INT_MAX, true},
     {"-2147483649", 0, false},
     {"-99999999999", 0, false},
-    {"2147483648", GG_UINT64_C(2147483648), true},
-    {"99999999999", GG_UINT64_C(99999999999), true},
+    {"2147483648", UINT64_C(2147483648), true},
+    {"99999999999", UINT64_C(99999999999), true},
     {"9223372036854775807", kint64max, true},
     {"-9223372036854775808", 0, false},
     {"09", 9, true},
@@ -327,7 +328,7 @@
     {"-", 0, false},
     {"-9223372036854775809", 0, false},
     {"-99999999999999999999", 0, false},
-    {"9223372036854775808", GG_UINT64_C(9223372036854775808), true},
+    {"9223372036854775808", UINT64_C(9223372036854775808), true},
     {"99999999999999999999", kuint64max, false},
     {"18446744073709551615", kuint64max, true},
     {"18446744073709551616", kuint64max, false},
@@ -550,7 +551,7 @@
     {"42", 66, true},
     {"-42", -66, true},
     {"+42", 66, true},
-    {"40acd88557b", GG_INT64_C(4444444448123), true},
+    {"40acd88557b", INT64_C(4444444448123), true},
     {"7fffffff", INT_MAX, true},
     {"-80000000", INT_MIN, true},
     {"ffffffff", 0xffffffff, true},
@@ -558,7 +559,7 @@
     {"0x42", 66, true},
     {"-0x42", -66, true},
     {"+0x42", 66, true},
-    {"0x40acd88557b", GG_INT64_C(4444444448123), true},
+    {"0x40acd88557b", INT64_C(4444444448123), true},
     {"0x7fffffff", INT_MAX, true},
     {"-0x80000000", INT_MIN, true},
     {"0xffffffff", 0xffffffff, true},
@@ -607,7 +608,7 @@
     {"42", 66, true},
     {"-42", 0, false},
     {"+42", 66, true},
-    {"40acd88557b", GG_INT64_C(4444444448123), true},
+    {"40acd88557b", INT64_C(4444444448123), true},
     {"7fffffff", INT_MAX, true},
     {"-80000000", 0, false},
     {"ffffffff", 0xffffffff, true},
@@ -615,14 +616,14 @@
     {"0x42", 66, true},
     {"-0x42", 0, false},
     {"+0x42", 66, true},
-    {"0x40acd88557b", GG_INT64_C(4444444448123), true},
+    {"0x40acd88557b", INT64_C(4444444448123), true},
     {"0x7fffffff", INT_MAX, true},
     {"-0x80000000", 0, false},
     {"0xffffffff", 0xffffffff, true},
     {"0XDeadBeef", 0xdeadbeef, true},
     {"0x7fffffffffffffff", kint64max, true},
     {"-0x8000000000000000", 0, false},
-    {"0x8000000000000000", GG_UINT64_C(0x8000000000000000), true},
+    {"0x8000000000000000", UINT64_C(0x8000000000000000), true},
     {"-0x8000000000000001", 0, false},
     {"0xFFFFFFFFFFFFFFFF", kuint64max, true},
     {"FFFFFFFFFFFFFFFF", kuint64max, true},
diff --git a/base/strings/string_piece.cc b/base/strings/string_piece.cc
index 4c7f112..db0433a 100644
--- a/base/strings/string_piece.cc
+++ b/base/strings/string_piece.cc
@@ -8,6 +8,8 @@
 #include <algorithm>
 #include <ostream>
 
+#include "base/logging.h"
+
 namespace base {
 namespace {
 
@@ -433,5 +435,16 @@
   return substrT(self, pos, n);
 }
 
+#if DCHECK_IS_ON()
+void AssertIteratorsInOrder(std::string::const_iterator begin,
+                            std::string::const_iterator end) {
+  DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
+}
+void AssertIteratorsInOrder(string16::const_iterator begin,
+                            string16::const_iterator end) {
+  DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
+}
+#endif
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
index 349018b..eb82d33 100644
--- a/base/strings/string_piece.h
+++ b/base/strings/string_piece.h
@@ -18,12 +18,6 @@
 // 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_
@@ -36,6 +30,7 @@
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/containers/hash_tables.h"
+#include "base/logging.h"
 #include "base/strings/string16.h"
 
 namespace base {
@@ -149,6 +144,14 @@
                                  size_t pos,
                                  size_t n);
 
+#if DCHECK_IS_ON()
+// Asserts that begin <= end to catch some errors with iterator usage.
+BASE_EXPORT void AssertIteratorsInOrder(std::string::const_iterator begin,
+                                        std::string::const_iterator end);
+BASE_EXPORT void AssertIteratorsInOrder(string16::const_iterator begin,
+                                        string16::const_iterator end);
+#endif
+
 }  // namespace internal
 
 // BasicStringPiece ------------------------------------------------------------
@@ -186,9 +189,18 @@
   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) {}
+                   const typename STRING_TYPE::const_iterator& end) {
+#if DCHECK_IS_ON()
+    // This assertion is done out-of-line to avoid bringing in logging.h and
+    // instantiating logging macros for every instantiation.
+    internal::AssertIteratorsInOrder(begin, end);
+#endif
+    length_ = static_cast<size_t>(std::distance(begin, end));
+
+    // The length test before assignment is to avoid dereferencing an iterator
+    // that may point to the end() of a string.
+    ptr_ = length_ > 0 ? &*begin : nullptr;
+  }
 
   // data() may return a pointer to a buffer with embedded NULs, and the
   // returned buffer may or may not be null terminated.  Therefore it is
diff --git a/base/strings/string_split.cc b/base/strings/string_split.cc
index 88a6236..4253e2f 100644
--- a/base/strings/string_split.cc
+++ b/base/strings/string_split.cc
@@ -12,201 +12,229 @@
 
 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;
-    }
-  }
+// PieceToOutputType converts a StringPiece as needed to a given output type,
+// which is either the same type of StringPiece (a NOP) or the corresponding
+// non-piece string type.
+//
+// The default converter is a NOP, it works when the OutputType is the
+// correct StringPiece.
+template<typename Str, typename OutputType>
+OutputType PieceToOutputType(BasicStringPiece<Str> piece) {
+  return piece;
+}
+template<>  // Convert StringPiece to std::string
+std::string PieceToOutputType<std::string, std::string>(StringPiece piece) {
+  return piece.as_string();
+}
+template<>  // Convert StringPiece16 to string16.
+string16 PieceToOutputType<string16, string16>(StringPiece16 piece) {
+  return piece.as_string();
 }
 
-bool SplitStringIntoKeyValue(const std::string& line,
-                             char key_value_delimiter,
-                             std::string* key,
-                             std::string* value) {
-  key->clear();
-  value->clear();
+// Returns either the ASCII or UTF-16 whitespace.
+template<typename Str> BasicStringPiece<Str> WhitespaceForType();
+template<> StringPiece16 WhitespaceForType<string16>() {
+  return kWhitespaceUTF16;
+}
+template<> StringPiece WhitespaceForType<std::string>() {
+  return kWhitespaceASCII;
+}
+
+// Optimize the single-character case to call find() on the string instead,
+// since this is the common case and can be made faster. This could have been
+// done with template specialization too, but would have been less clear.
+//
+// There is no corresponding FindFirstNotOf because StringPiece already
+// implements these different versions that do the optimized searching.
+size_t FindFirstOf(StringPiece piece, char c, size_t pos) {
+  return piece.find(c, pos);
+}
+size_t FindFirstOf(StringPiece16 piece, char16 c, size_t pos) {
+  return piece.find(c, pos);
+}
+size_t FindFirstOf(StringPiece piece, StringPiece one_of, size_t pos) {
+  return piece.find_first_of(one_of, pos);
+}
+size_t FindFirstOf(StringPiece16 piece, StringPiece16 one_of, size_t pos) {
+  return piece.find_first_of(one_of, pos);
+}
+
+// General string splitter template. Can take 8- or 16-bit input, can produce
+// the corresponding string or StringPiece output, and can take single- or
+// multiple-character delimiters.
+//
+// DelimiterType is either a character (Str::value_type) or a string piece of
+// multiple characters (BasicStringPiece<Str>). StringPiece has a version of
+// find for both of these cases, and the single-character version is the most
+// common and can be implemented faster, which is why this is a template.
+template<typename Str, typename OutputStringType, typename DelimiterType>
+static std::vector<OutputStringType> SplitStringT(
+    BasicStringPiece<Str> str,
+    DelimiterType delimiter,
+    WhitespaceHandling whitespace,
+    SplitResult result_type) {
+  std::vector<OutputStringType> result;
+  if (str.empty())
+    return result;
+
+  size_t start = 0;
+  while (start != Str::npos) {
+    size_t end = FindFirstOf(str, delimiter, start);
+
+    BasicStringPiece<Str> piece;
+    if (end == Str::npos) {
+      piece = str.substr(start);
+      start = Str::npos;
+    } else {
+      piece = str.substr(start, end - start);
+      start = end + 1;
+    }
+
+    if (whitespace == TRIM_WHITESPACE)
+      piece = TrimString(piece, WhitespaceForType<Str>(), TRIM_ALL);
+
+    if (result_type == SPLIT_WANT_ALL || !piece.empty())
+      result.push_back(PieceToOutputType<Str, OutputStringType>(piece));
+  }
+  return result;
+}
+
+bool AppendStringKeyValue(StringPiece input,
+                          char delimiter,
+                          StringPairs* result) {
+  // Always append a new item regardless of success (it might be empty). The
+  // below code will copy the strings directly into the result pair.
+  result->resize(result->size() + 1);
+  auto& result_pair = result->back();
 
   // Find the delimiter.
-  size_t end_key_pos = line.find_first_of(key_value_delimiter);
+  size_t end_key_pos = input.find_first_of(delimiter);
   if (end_key_pos == std::string::npos) {
-    DVLOG(1) << "cannot find delimiter in: " << line;
-    return false;    // no delimiter
+    DVLOG(1) << "cannot find delimiter in: " << input;
+    return false;    // No delimiter.
   }
-  key->assign(line, 0, end_key_pos);
+  input.substr(0, end_key_pos).CopyToString(&result_pair.first);
 
   // 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
+  StringPiece remains = input.substr(end_key_pos, input.size() - end_key_pos);
+  size_t begin_value_pos = remains.find_first_not_of(delimiter);
+  if (begin_value_pos == StringPiece::npos) {
+    DVLOG(1) << "cannot parse value from input: " << input;
+    return false;   // No value.
   }
-  value->assign(remains, begin_value_pos, remains.size() - begin_value_pos);
+  remains.substr(begin_value_pos, remains.size() - begin_value_pos)
+      .CopyToString(&result_pair.second);
+
   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;
+template <typename Str>
+void SplitStringUsingSubstrT(BasicStringPiece<Str> input,
+                             BasicStringPiece<Str> delimiter,
+                             std::vector<Str>* result) {
+  using Piece = BasicStringPiece<Str>;
+  using size_type = typename Piece::size_type;
+
+  result->clear();
+  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);
+    size_type end_index = input.find(delimiter, begin_index);
+    if (end_index == Piece::npos) {
+      // No delimiter, use the rest of the string.
+      Piece term = TrimString(input.substr(begin_index),
+                              WhitespaceForType<Str>(), TRIM_ALL);
+      result->push_back(term.as_string());
       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));
+    Piece term = TrimString(input.substr(begin_index, end_index - begin_index),
+                            WhitespaceForType<Str>(), TRIM_ALL);
+    result->push_back(term.as_string());
+    begin_index = end_index + delimiter.size();
   }
 }
 
 }  // namespace
 
-void SplitString(const string16& str,
-                 char16 c,
-                 std::vector<string16>* r) {
-  DCHECK(CBU16_IS_SINGLE(c));
-  SplitStringT(str, c, true, r);
+std::vector<std::string> SplitString(StringPiece input,
+                                     StringPiece separators,
+                                     WhitespaceHandling whitespace,
+                                     SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<std::string, std::string, char>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<std::string, std::string, StringPiece>(
+      input, separators, whitespace, result_type);
 }
 
-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);
+std::vector<string16> SplitString(StringPiece16 input,
+                                  StringPiece16 separators,
+                                  WhitespaceHandling whitespace,
+                                  SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<string16, string16, char16>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<string16, string16, StringPiece16>(
+      input, separators, whitespace, result_type);
 }
 
-bool SplitStringIntoKeyValuePairs(const std::string& line,
+std::vector<StringPiece> SplitStringPiece(StringPiece input,
+                                          StringPiece separators,
+                                          WhitespaceHandling whitespace,
+                                          SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<std::string, StringPiece, char>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<std::string, StringPiece, StringPiece>(
+      input, separators, whitespace, result_type);
+}
+
+std::vector<StringPiece16> SplitStringPiece(StringPiece16 input,
+                                            StringPiece16 separators,
+                                            WhitespaceHandling whitespace,
+                                            SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<string16, StringPiece16, char16>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<string16, StringPiece16, StringPiece16>(
+      input, separators, whitespace, result_type);
+}
+
+bool SplitStringIntoKeyValuePairs(StringPiece input,
                                   char key_value_delimiter,
                                   char key_value_pair_delimiter,
                                   StringPairs* key_value_pairs) {
   key_value_pairs->clear();
 
-  std::vector<std::string> pairs;
-  SplitString(line, key_value_pair_delimiter, &pairs);
+  std::vector<StringPiece> pairs = SplitStringPiece(
+      input, std::string(1, key_value_pair_delimiter),
+      TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  key_value_pairs->reserve(pairs.size());
 
   bool success = true;
-  for (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)) {
+  for (const StringPiece& pair : pairs) {
+    if (!AppendStringKeyValue(pair, key_value_delimiter, key_value_pairs)) {
       // Don't return here, to allow for pairs without associated
       // value or key; just record that the split failed.
       success = false;
     }
-    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(StringPiece16 input,
+                            StringPiece16 delimiter,
+                            std::vector<string16>* result) {
+  SplitStringUsingSubstrT(input, delimiter, result);
 }
 
-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);
+void SplitStringUsingSubstr(StringPiece input,
+                            StringPiece delimiter,
+                            std::vector<std::string>* result) {
+  SplitStringUsingSubstrT(input, delimiter, result);
 }
 
 }  // namespace base
diff --git a/base/strings/string_split.h b/base/strings/string_split.h
index 55d8cb3..2a0c795 100644
--- a/base/strings/string_split.h
+++ b/base/strings/string_split.h
@@ -11,71 +11,95 @@
 
 #include "base/base_export.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_piece.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.
+enum WhitespaceHandling {
+  KEEP_WHITESPACE,
+  TRIM_WHITESPACE,
+};
+
+enum SplitResult {
+  // Strictly return all results.
+  //
+  // If the input is ",," and the separator is ',' this will return a
+  // vector of three empty strings.
+  SPLIT_WANT_ALL,
+
+  // Only nonempty results will be added to the results. Multiple separators
+  // will be coalesced. Separators at the beginning and end of the input will
+  // be ignored. With TRIM_WHITESPACE, whitespace-only results will be dropped.
+  //
+  // If the input is ",," and the separator is ',', this will return an empty
+  // vector.
+  SPLIT_WANT_NONEMPTY,
+};
+
+// Split the given string on ANY of the given separators, returning copies of
+// the result.
 //
-// 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);
+// To split on either commas or semicolons, keeping all whitespace:
+//
+//   std::vector<std::string> tokens = base::SplitString(
+//       input, ",;", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+BASE_EXPORT std::vector<std::string> SplitString(
+    StringPiece input,
+    StringPiece separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+BASE_EXPORT std::vector<string16> SplitString(
+    StringPiece16 input,
+    StringPiece16 separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
 
-// |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);
+// Like SplitString above except it returns a vector of StringPieces which
+// reference the original buffer without copying. Although you have to be
+// careful to keep the original string unmodified, this provides an efficient
+// way to iterate through tokens in a string.
+//
+// To iterate through all whitespace-separated tokens in an input string:
+//
+//   for (const auto& cur :
+//        base::SplitStringPiece(input, base::kWhitespaceASCII,
+//                               base::KEEP_WHITESPACE,
+//                               base::SPLIT_WANT_NONEMPTY)) {
+//     ...
+BASE_EXPORT std::vector<StringPiece> SplitStringPiece(
+    StringPiece input,
+    StringPiece separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+BASE_EXPORT std::vector<StringPiece16> SplitStringPiece(
+    StringPiece16 input,
+    StringPiece16 separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
 
-typedef std::vector<std::pair<std::string, std::string> > StringPairs;
+using StringPairs = std::vector<std::pair<std::string, std::string>>;
 
 // Splits |line| into key value pairs according to the given delimiters and
 // removes whitespace leading each key and trailing each value. Returns true
 // only if each pair has a non-empty key and value. |key_value_pairs| will
 // include ("","") pairs for entries without |key_value_delimiter|.
-BASE_EXPORT bool SplitStringIntoKeyValuePairs(const std::string& line,
+BASE_EXPORT bool SplitStringIntoKeyValuePairs(StringPiece input,
                                               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.
+// Similar to SplitString, but use a substring delimiter instead of a list of
+// characters that are all possible delimiters.
 //
-// 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);
+// TODO(brettw) this should probably be changed and expanded to provide a
+// mirror of the SplitString[Piece] API above, just with the different
+// delimiter handling.
+BASE_EXPORT void SplitStringUsingSubstr(StringPiece16 input,
+                                        StringPiece16 delimiter,
+                                        std::vector<string16>* result);
+BASE_EXPORT void SplitStringUsingSubstr(StringPiece input,
+                                        StringPiece delimiter,
+                                        std::vector<std::string>* result);
 
 }  // namespace base
 
diff --git a/base/strings/string_split_unittest.cc b/base/strings/string_split_unittest.cc
index 32bbe28..0416776 100644
--- a/base/strings/string_split_unittest.cc
+++ b/base/strings/string_split_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/strings/string_split.h"
 
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -12,23 +13,6 @@
 
 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;
@@ -169,68 +153,78 @@
   EXPECT_THAT(results, ElementsAre(""));
 }
 
-TEST(StringUtilTest, SplitString) {
-  std::vector<std::wstring> r;
+TEST(StringUtilTest, SplitString_Basics) {
+  std::vector<std::string> r;
 
-  SplitString(std::wstring(), L',', &r);
-  EXPECT_EQ(0U, r.size());
-  r.clear();
+  r = SplitString(std::string(), ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  EXPECT_TRUE(r.empty());
 
-  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();
+  // Empty separator list
+  r = SplitString("hello, world", "", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(1u, r.size());
+  EXPECT_EQ("hello, world", r[0]);
 
-  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();
+  // Should split on any of the separators.
+  r = SplitString("::,,;;", ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(7u, r.size());
+  for (auto str : r)
+    ASSERT_TRUE(str.empty());
 
-  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();
+  r = SplitString("red, green; blue:", ",:;", TRIM_WHITESPACE,
+                  SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("red", r[0]);
+  EXPECT_EQ("green", r[1]);
+  EXPECT_EQ("blue", r[2]);
 
-  SplitString(L"   ", L'*', &r);
-  EXPECT_EQ(0U, r.size());
-  r.clear();
+  // Want to split a string along whitespace sequences.
+  r = SplitString("  red green   \tblue\n", " \t\n", TRIM_WHITESPACE,
+                  SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("red", r[0]);
+  EXPECT_EQ("green", r[1]);
+  EXPECT_EQ("blue", r[2]);
 
-  SplitString(L"foo", L'*', &r);
-  ASSERT_EQ(1U, r.size());
-  EXPECT_EQ(r[0], L"foo");
-  r.clear();
+  // Weird case of splitting on spaces but not trimming.
+  r = SplitString(" red ", " ", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("", r[0]);  // Before the first space.
+  EXPECT_EQ("red", r[1]);
+  EXPECT_EQ("", r[2]);  // After the last space.
+}
 
-  SplitString(L"foo ,", L',', &r);
-  ASSERT_EQ(2U, r.size());
-  EXPECT_EQ(r[0], L"foo");
-  EXPECT_EQ(r[1], L"");
-  r.clear();
+TEST(StringUtilTest, SplitString_WhitespaceAndResultType) {
+  std::vector<std::string> r;
 
-  SplitString(L",", L',', &r);
-  ASSERT_EQ(2U, r.size());
-  EXPECT_EQ(r[0], L"");
-  EXPECT_EQ(r[1], L"");
-  r.clear();
+  // Empty input handling.
+  r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  EXPECT_TRUE(r.empty());
+  r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  EXPECT_TRUE(r.empty());
 
-  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();
+  // Input string is space and we're trimming.
+  r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(1u, r.size());
+  EXPECT_EQ("", r[0]);
+  r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  EXPECT_TRUE(r.empty());
 
-  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 all 4 combinations of flags on ", ,".
+  r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("", r[0]);
+  EXPECT_EQ(" ", r[1]);
+  EXPECT_EQ("", r[2]);
+  r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(1u, r.size());
+  ASSERT_EQ(" ", r[0]);
+  r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("", r[0]);
+  EXPECT_EQ("", r[1]);
+  EXPECT_EQ("", r[2]);
+  r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  ASSERT_TRUE(r.empty());
 }
 
 TEST(SplitStringUsingSubstrTest, StringWithNoDelimiter) {
@@ -271,21 +265,23 @@
       results, ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
 }
 
-TEST(StringSplitTest, StringSplitDontTrim) {
+TEST(StringSplitTest, StringSplitKeepWhitespace) {
   std::vector<std::string> r;
 
-  SplitStringDontTrim("   ", '*', &r);
+  r = SplitString("   ", "*", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
   ASSERT_EQ(1U, r.size());
   EXPECT_EQ(r[0], "   ");
 
-  SplitStringDontTrim("\t  \ta\t ", '\t', &r);
+  r = SplitString("\t  \ta\t ", "\t", base::KEEP_WHITESPACE,
+                  base::SPLIT_WANT_ALL);
   ASSERT_EQ(4U, r.size());
   EXPECT_EQ(r[0], "");
   EXPECT_EQ(r[1], "  ");
   EXPECT_EQ(r[2], "a");
   EXPECT_EQ(r[3], " ");
 
-  SplitStringDontTrim("\ta\t\nb\tcc", '\n', &r);
+  r = SplitString("\ta\t\nb\tcc", "\n", base::KEEP_WHITESPACE,
+                  base::SPLIT_WANT_ALL);
   ASSERT_EQ(2U, r.size());
   EXPECT_EQ(r[0], "\ta\t");
   EXPECT_EQ(r[1], "b\tcc");
@@ -313,8 +309,9 @@
     { "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);
+    std::vector<std::string> results = base::SplitString(
+        data[i].input, kWhitespaceASCII, base::KEEP_WHITESPACE,
+        base::SPLIT_WANT_NONEMPTY);
     ASSERT_EQ(data[i].expected_result_count, results.size());
     if (data[i].expected_result_count > 0)
       ASSERT_EQ(data[i].output1, results[0]);
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index 6f6d6e2..731a77d 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -21,14 +21,13 @@
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
+#include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversion_utils.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/third_party/icu/icu_utf.h"
 #include "build/build_config.h"
 
-// Remove when this entire file is in the base namespace.
-using base::char16;
-using base::string16;
+namespace base {
 
 namespace {
 
@@ -79,13 +78,13 @@
 }
 
 template<size_t size, typename CharacterType> struct NonASCIIMask;
-template<> struct NonASCIIMask<4, base::char16> {
+template<> struct NonASCIIMask<4, char16> {
     static inline uint32_t value() { return 0xFF80FF80U; }
 };
 template<> struct NonASCIIMask<4, char> {
     static inline uint32_t value() { return 0x80808080U; }
 };
-template<> struct NonASCIIMask<8, base::char16> {
+template<> struct NonASCIIMask<8, char16> {
     static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; }
 };
 template<> struct NonASCIIMask<8, char> {
@@ -102,8 +101,6 @@
 
 }  // namespace
 
-namespace base {
-
 bool IsWprintfFormatPortable(const wchar_t* format) {
   for (const wchar_t* position = format; *position != '\0'; ++position) {
     if (*position == '%') {
@@ -139,6 +136,91 @@
   return true;
 }
 
+namespace {
+
+template<typename StringType>
+StringType ToLowerASCIIImpl(BasicStringPiece<StringType> str) {
+  StringType ret;
+  ret.reserve(str.size());
+  for (size_t i = 0; i < str.size(); i++)
+    ret.push_back(ToLowerASCII(str[i]));
+  return ret;
+}
+
+template<typename StringType>
+StringType ToUpperASCIIImpl(BasicStringPiece<StringType> str) {
+  StringType ret;
+  ret.reserve(str.size());
+  for (size_t i = 0; i < str.size(); i++)
+    ret.push_back(ToUpperASCII(str[i]));
+  return ret;
+}
+
+}  // namespace
+
+std::string ToLowerASCII(StringPiece str) {
+  return ToLowerASCIIImpl<std::string>(str);
+}
+
+string16 ToLowerASCII(StringPiece16 str) {
+  return ToLowerASCIIImpl<string16>(str);
+}
+
+std::string ToUpperASCII(StringPiece str) {
+  return ToUpperASCIIImpl<std::string>(str);
+}
+
+string16 ToUpperASCII(StringPiece16 str) {
+  return ToUpperASCIIImpl<string16>(str);
+}
+
+template<class StringType>
+int CompareCaseInsensitiveASCIIT(BasicStringPiece<StringType> a,
+                                 BasicStringPiece<StringType> b) {
+  // Find the first characters that aren't equal and compare them.  If the end
+  // of one of the strings is found before a nonequal character, the lengths
+  // of the strings are compared.
+  size_t i = 0;
+  while (i < a.length() && i < b.length()) {
+    typename StringType::value_type lower_a = ToLowerASCII(a[i]);
+    typename StringType::value_type lower_b = ToLowerASCII(b[i]);
+    if (lower_a < lower_b)
+      return -1;
+    if (lower_a > lower_b)
+      return 1;
+    i++;
+  }
+
+  // End of one string hit before finding a different character. Expect the
+  // common case to be "strings equal" at this point so check that first.
+  if (a.length() == b.length())
+    return 0;
+
+  if (a.length() < b.length())
+    return -1;
+  return 1;
+}
+
+int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+  return CompareCaseInsensitiveASCIIT<std::string>(a, b);
+}
+
+int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+  return CompareCaseInsensitiveASCIIT<string16>(a, b);
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+  if (a.length() != b.length())
+    return false;
+  return CompareCaseInsensitiveASCIIT<std::string>(a, b) == 0;
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+  if (a.length() != b.length())
+    return false;
+  return CompareCaseInsensitiveASCIIT<string16>(a, b) == 0;
+}
+
 const std::string& EmptyString() {
   return EmptyStrings::GetInstance()->s;
 }
@@ -168,54 +250,58 @@
 }
 
 bool ReplaceChars(const string16& input,
-                  const base::StringPiece16& replace_chars,
+                  const StringPiece16& replace_chars,
                   const string16& replace_with,
                   string16* output) {
   return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
 }
 
 bool ReplaceChars(const std::string& input,
-                  const base::StringPiece& replace_chars,
+                  const StringPiece& replace_chars,
                   const std::string& replace_with,
                   std::string* output) {
   return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
 }
 
 bool RemoveChars(const string16& input,
-                 const base::StringPiece16& remove_chars,
+                 const 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,
+                 const StringPiece& remove_chars,
                  std::string* output) {
   return ReplaceChars(input, remove_chars.as_string(), std::string(), output);
 }
 
-template<typename STR>
-TrimPositions TrimStringT(const STR& input,
-                          const STR& trim_chars,
+template<typename Str>
+TrimPositions TrimStringT(const Str& input,
+                          BasicStringPiece<Str> trim_chars,
                           TrimPositions positions,
-                          STR* output) {
-  // Find the edges of leading/trailing whitespace as desired.
+                          Str* output) {
+  // Find the edges of leading/trailing whitespace as desired. Need to use
+  // a StringPiece version of input to be able to call find* on it with the
+  // StringPiece version of trim_chars (normally the trim_chars will be a
+  // constant so avoid making a copy).
+  BasicStringPiece<Str> input_piece(input);
   const size_t last_char = input.length() - 1;
   const size_t first_good_char = (positions & TRIM_LEADING) ?
-      input.find_first_not_of(trim_chars) : 0;
+      input_piece.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;
+      input_piece.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|.
+  // When the string was all trimmed, report that we stripped off characters
+  // from whichever position the caller was interested in. For empty input, we
+  // stripped no characters, but we still need to clear |output|.
   if (input.empty() ||
-      (first_good_char == STR::npos) || (last_good_char == STR::npos)) {
+      (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.
+  // Trim.
   *output =
       input.substr(first_good_char, last_good_char - first_good_char + 1);
 
@@ -226,17 +312,38 @@
 }
 
 bool TrimString(const string16& input,
-                const base::StringPiece16& trim_chars,
+                StringPiece16 trim_chars,
                 string16* output) {
-  return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) !=
-      TRIM_NONE;
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
 }
 
 bool TrimString(const std::string& input,
-                const base::StringPiece& trim_chars,
+                StringPiece trim_chars,
                 std::string* output) {
-  return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) !=
-      TRIM_NONE;
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+template<typename Str>
+BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input,
+                                       BasicStringPiece<Str> trim_chars,
+                                       TrimPositions positions) {
+  size_t begin = (positions & TRIM_LEADING) ?
+      input.find_first_not_of(trim_chars) : 0;
+  size_t end = (positions & TRIM_TRAILING) ?
+      input.find_last_not_of(trim_chars) + 1 : input.size();
+  return input.substr(begin, end - begin);
+}
+
+StringPiece16 TrimString(StringPiece16 input,
+                         const StringPiece16& trim_chars,
+                         TrimPositions positions) {
+  return TrimStringPieceT(input, trim_chars, positions);
+}
+
+StringPiece TrimString(StringPiece input,
+                       const StringPiece& trim_chars,
+                       TrimPositions positions) {
+  return TrimStringPieceT(input, trim_chars, positions);
 }
 
 void TruncateUTF8ToByteSize(const std::string& input,
@@ -278,14 +385,22 @@
 TrimPositions TrimWhitespace(const string16& input,
                              TrimPositions positions,
                              string16* output) {
-  return TrimStringT(input, base::string16(kWhitespaceUTF16), positions,
-                     output);
+  return TrimStringT(input, StringPiece16(kWhitespaceUTF16), positions, output);
+}
+
+StringPiece16 TrimWhitespace(StringPiece16 input,
+                             TrimPositions positions) {
+  return TrimStringPieceT(input, StringPiece16(kWhitespaceUTF16), positions);
 }
 
 TrimPositions TrimWhitespaceASCII(const std::string& input,
                                   TrimPositions positions,
                                   std::string* output) {
-  return TrimStringT(input, std::string(kWhitespaceASCII), positions, output);
+  return TrimStringT(input, StringPiece(kWhitespaceASCII), positions, output);
+}
+
+StringPiece TrimWhitespaceASCII(StringPiece input, TrimPositions positions) {
+  return TrimStringPieceT(input, StringPiece(kWhitespaceASCII), positions);
 }
 
 // This function is only for backward-compatibility.
@@ -309,7 +424,7 @@
 
   int chars_written = 0;
   for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
-    if (IsWhitespace(*i)) {
+    if (IsUnicodeWhitespace(*i)) {
       if (!in_whitespace) {
         // Reduce all whitespace sequences to a single space.
         in_whitespace = true;
@@ -420,105 +535,140 @@
   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)
+// Implementation note: Normally this function will be called with a hardcoded
+// constant for the lowercase_ascii parameter. Constructing a StringPiece from
+// a C constant requires running strlen, so the result will be two passes
+// through the buffers, one to file the length of lowercase_ascii, and one to
+// compare each letter.
+//
+// This function could have taken a const char* to avoid this and only do one
+// pass through the string. But the strlen is faster than the case-insensitive
+// compares and lets us early-exit in the case that the strings are different
+// lengths (will often be the case for non-matches). So whether one approach or
+// the other will be faster depends on the case.
+//
+// The hardcoded strings are typically very short so it doesn't matter, and the
+// string piece gives additional flexibility for the caller (doesn't have to be
+// null terminated) so we choose the StringPiece route.
+template<typename Str>
+static inline bool DoLowerCaseEqualsASCII(BasicStringPiece<Str> str,
+                                          StringPiece lowercase_ascii) {
+  if (str.size() != lowercase_ascii.size())
+    return false;
+  for (size_t i = 0; i < str.size(); i++) {
+    if (ToLowerASCII(str[i]) != lowercase_ascii[i])
       return false;
   }
-  return *b == 0;
+  return true;
 }
 
-// Front-ends for LowerCaseEqualsASCII.
-bool LowerCaseEqualsASCII(const std::string& a, const char* b) {
-  return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+bool LowerCaseEqualsASCII(StringPiece str, StringPiece lowercase_ascii) {
+  return DoLowerCaseEqualsASCII<std::string>(str, lowercase_ascii);
 }
 
-bool LowerCaseEqualsASCII(const string16& a, const char* b) {
-  return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+bool LowerCaseEqualsASCII(StringPiece16 str, StringPiece lowercase_ascii) {
+  return DoLowerCaseEqualsASCII<string16>(str, lowercase_ascii);
 }
 
-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())
+bool EqualsASCII(StringPiece16 str, StringPiece ascii) {
+  if (str.length() != ascii.length())
     return false;
-  return std::equal(b.begin(), b.end(), a.begin());
+  return std::equal(ascii.begin(), ascii.end(), str.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(BasicStringPiece<Str> str,
+                 BasicStringPiece<Str> search_for,
+                 CompareCase case_sensitivity) {
+  if (search_for.size() > str.size())
+    return false;
 
-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())
+  BasicStringPiece<Str> source = str.substr(0, search_for.size());
+
+  switch (case_sensitivity) {
+    case CompareCase::SENSITIVE:
+      return source == search_for;
+
+    case CompareCase::INSENSITIVE_ASCII:
+      return std::equal(
+          search_for.begin(), search_for.end(),
+          source.begin(),
+          CaseInsensitiveCompareASCII<typename Str::value_type>());
+
+    default:
+      NOTREACHED();
       return false;
-    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);
+bool StartsWith(StringPiece str,
+                StringPiece search_for,
+                CompareCase case_sensitivity) {
+  return StartsWithT<std::string>(str, search_for, case_sensitivity);
 }
 
-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)
+bool StartsWith(StringPiece16 str,
+                StringPiece16 search_for,
+                CompareCase case_sensitivity) {
+  return StartsWithT<string16>(str, search_for, case_sensitivity);
+}
+
+template <typename Str>
+bool EndsWithT(BasicStringPiece<Str> str,
+               BasicStringPiece<Str> search_for,
+               CompareCase case_sensitivity) {
+  if (search_for.size() > str.size())
     return false;
-  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>());
+
+  BasicStringPiece<Str> source = str.substr(str.size() - search_for.size(),
+                                            search_for.size());
+
+  switch (case_sensitivity) {
+    case CompareCase::SENSITIVE:
+      return source == search_for;
+
+    case CompareCase::INSENSITIVE_ASCII:
+      return std::equal(
+          source.begin(), source.end(),
+          search_for.begin(),
+          CaseInsensitiveCompareASCII<typename Str::value_type>());
+
+    default:
+      NOTREACHED();
+      return false;
+  }
 }
 
-bool EndsWith(const std::string& str, const std::string& search,
-              bool case_sensitive) {
-  return EndsWithT(str, search, case_sensitive);
+bool EndsWith(StringPiece str,
+              StringPiece search_for,
+              CompareCase case_sensitivity) {
+  return EndsWithT<std::string>(str, search_for, case_sensitivity);
 }
 
-bool EndsWith(const string16& str, const string16& search,
-              bool case_sensitive) {
-  return EndsWithT(str, search, case_sensitive);
+bool EndsWith(StringPiece16 str,
+              StringPiece16 search_for,
+              CompareCase case_sensitivity) {
+  return EndsWithT<string16>(str, search_for, case_sensitivity);
+}
+
+char HexDigitToInt(wchar_t c) {
+  DCHECK(IsHexDigit(c));
+  if (c >= '0' && c <= '9')
+    return static_cast<char>(c - '0');
+  if (c >= 'A' && c <= 'F')
+    return static_cast<char>(c - 'A' + 10);
+  if (c >= 'a' && c <= 'f')
+    return static_cast<char>(c - 'a' + 10);
+  return 0;
+}
+
+bool IsUnicodeWhitespace(wchar_t c) {
+  // kWhitespaceWide is a NULL-terminated string
+  for (const wchar_t* cur = kWhitespaceWide; *cur; ++cur) {
+    if (*cur == c)
+      return true;
+  }
+  return false;
 }
 
 static const char* const kByteStringsUnlocalized[] = {
@@ -549,20 +699,20 @@
                    kByteStringsUnlocalized[dimension]);
   }
 
-  return base::ASCIIToUTF16(buf);
+  return 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,
+                                    BasicStringPiece<StringType> find_this,
+                                    BasicStringPiece<StringType> replace_with,
                                     bool replace_all) {
   DCHECK(!find_this.empty());
 
   // If the find string doesn't appear, there's nothing to do.
-  offset = str->find(find_this, offset);
+  offset = str->find(find_this.data(), offset, find_this.size());
   if (offset == StringType::npos)
     return;
 
@@ -570,7 +720,7 @@
   // complicated.
   size_t find_length = find_this.length();
   if (!replace_all) {
-    str->replace(offset, find_length, replace_with);
+    str->replace(offset, find_length, replace_with.data(), replace_with.size());
     return;
   }
 
@@ -579,8 +729,10 @@
   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);
+      str->replace(offset, find_length,
+                   replace_with.data(), replace_with.size());
+      offset = str->find(find_this.data(), offset + replace_length,
+                         find_this.size());
     } while (offset != StringType::npos);
     return;
   }
@@ -597,11 +749,14 @@
     size_t write_offset = offset;
     do {
       if (replace_length) {
-        str->replace(write_offset, replace_length, replace_with);
+        str->replace(write_offset, replace_length,
+                     replace_with.data(), replace_with.size());
         write_offset += replace_length;
       }
       size_t read_offset = offset + find_length;
-      offset = std::min(str->find(find_this, read_offset), str_length);
+      offset = std::min(
+          str->find(find_this.data(), read_offset, find_this.size()),
+          str_length);
       size_t length = offset - read_offset;
       if (length) {
         memmove(&(*str)[write_offset], &(*str)[read_offset],
@@ -630,13 +785,15 @@
     // 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);
+    offset = str->find(find_this.data(), offset + find_length,
+                       find_this.size());
   } while (offset != StringType::npos);
   str->resize(final_length);
 
   // Now do the replacement loop, working backwards through the string.
   for (size_t prev_match = str_length, write_offset = final_length; ;
-       current_match = str->rfind(find_this, current_match - 1)) {
+       current_match = str->rfind(find_this.data(), current_match - 1,
+                                  find_this.size())) {
     size_t read_offset = current_match + find_length;
     size_t length = prev_match - read_offset;
     if (length) {
@@ -645,7 +802,8 @@
               length * sizeof(typename StringType::value_type));
     }
     write_offset -= replace_length;
-    str->replace(write_offset, replace_length, replace_with);
+    str->replace(write_offset, replace_length,
+                 replace_with.data(), replace_with.size());
     if (current_match == first_match)
       return;
     prev_match = current_match;
@@ -654,128 +812,97 @@
 
 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
+                                      StringPiece16 find_this,
+                                      StringPiece16 replace_with) {
+  DoReplaceSubstringsAfterOffset<string16>(
+      str, start_offset, find_this, replace_with, false);  // Replace first.
 }
 
 void ReplaceFirstSubstringAfterOffset(std::string* str,
                                       size_t start_offset,
-                                      const std::string& find_this,
-                                      const std::string& replace_with) {
-  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
-                                 false);  // replace first instance
+                                      StringPiece find_this,
+                                      StringPiece replace_with) {
+  DoReplaceSubstringsAfterOffset<std::string>(
+      str, start_offset, find_this, replace_with, false);  // Replace first.
 }
 
 void ReplaceSubstringsAfterOffset(string16* str,
                                   size_t start_offset,
-                                  const string16& find_this,
-                                  const string16& replace_with) {
-  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
-                                 true);  // replace all instances
+                                  StringPiece16 find_this,
+                                  StringPiece16 replace_with) {
+  DoReplaceSubstringsAfterOffset<string16>(
+      str, start_offset, find_this, replace_with, true);  // Replace all.
 }
 
 void ReplaceSubstringsAfterOffset(std::string* str,
                                   size_t start_offset,
-                                  const std::string& find_this,
-                                  const std::string& replace_with) {
-  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
-                                 true);  // replace all instances
+                                  StringPiece find_this,
+                                  StringPiece replace_with) {
+  DoReplaceSubstringsAfterOffset<std::string>(
+      str, start_offset, find_this, replace_with, true);  // Replace all.
 }
 
-
-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();
+template <class string_type>
+inline typename string_type::value_type* WriteIntoT(string_type* str,
+                                                    size_t length_with_null) {
+  DCHECK_GT(length_with_null, 1u);
+  str->reserve(length_with_null);
+  str->resize(length_with_null - 1);
+  return &((*str)[0]);
 }
 
-size_t Tokenize(const string16& str,
-                const string16& delimiters,
-                std::vector<string16>* tokens) {
-  return TokenizeT(str, delimiters, tokens);
+char* WriteInto(std::string* str, size_t length_with_null) {
+  return WriteIntoT(str, length_with_null);
 }
 
-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);
+char16* WriteInto(string16* str, size_t length_with_null) {
+  return WriteIntoT(str, length_with_null);
 }
 
 template<typename STR>
-static STR JoinStringT(const std::vector<STR>& parts, const STR& sep) {
+static STR JoinStringT(const std::vector<STR>& parts,
+                       BasicStringPiece<STR> sep) {
   if (parts.empty())
     return STR();
 
   STR result(parts[0]);
-  typename std::vector<STR>::const_iterator iter = parts.begin();
+  auto iter = parts.begin();
   ++iter;
 
   for (; iter != parts.end(); ++iter) {
-    result += sep;
+    sep.AppendToString(&result);
     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) {
+                       StringPiece separator) {
   return JoinStringT(parts, separator);
 }
 
 string16 JoinString(const std::vector<string16>& parts,
-                    const string16& separator) {
+                    StringPiece16 separator) {
   return JoinStringT(parts, separator);
 }
 
 template<class FormatStringType, class OutStringType>
-OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
-    const std::vector<OutStringType>& subst, std::vector<size_t>* offsets) {
+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();
-  }
+  for (const auto& cur : subst)
+    sub_length += cur.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) {
+  for (auto i = format_string.begin(); i != format_string.end(); ++i) {
     if ('$' == *i) {
       if (i + 1 != format_string.end()) {
         ++i;
@@ -813,10 +940,8 @@
     }
   }
   if (offsets) {
-    for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin();
-         i != r_offsets.end(); ++i) {
-      offsets->push_back(i->offset);
-    }
+    for (const auto& cur : r_offsets)
+      offsets->push_back(cur.offset);
   }
   return formatted;
 }
@@ -827,7 +952,7 @@
   return DoReplaceStringPlaceholders(format_string, subst, offsets);
 }
 
-std::string ReplaceStringPlaceholders(const base::StringPiece& format_string,
+std::string ReplaceStringPlaceholders(const StringPiece& format_string,
                                       const std::vector<std::string>& subst,
                                       std::vector<size_t>* offsets) {
   return DoReplaceStringPlaceholders(format_string, subst, offsets);
@@ -847,161 +972,6 @@
   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
@@ -1026,9 +996,11 @@
 
 }  // namespace
 
-size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
+size_t 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) {
+size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
   return lcpyT<wchar_t>(dst, src, dst_size);
 }
+
+}  // namespace base
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 5ab2ad5..3976111 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -21,23 +21,10 @@
 
 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);
+// C standard-library functions that aren't cross-platform are provided as
+// "base::...", and their prototypes are listed below. These functions are
+// then implemented as inline calls to the platform-specific equivalents in the
+// platform-specific headers.
 
 // Wrapper for vsnprintf that always null-terminates and always returns the
 // number of characters that would be in an untruncated formatted
@@ -49,9 +36,14 @@
 
 // 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, ...) {
+inline int snprintf(char* buffer,
+                    size_t size,
+                    _Printf_format_string_ const char* format,
+                    ...) PRINTF_FORMAT(3, 4);
+inline int snprintf(char* buffer,
+                    size_t size,
+                    _Printf_format_string_ const char* format,
+                    ...) {
   va_list arguments;
   va_start(arguments, format);
   int result = vsnprintf(buffer, size, format, arguments);
@@ -93,27 +85,38 @@
 
 // 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) {
+inline char ToLowerASCII(char c) {
+  return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+inline char16 ToLowerASCII(char16 c) {
   return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
 }
 
 // ASCII-specific toupper.  The standard library's toupper is locale sensitive,
 // so we don't want to use it here.
-template <class Char> inline Char ToUpperASCII(Char c) {
+inline char ToUpperASCII(char c) {
+  return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
+}
+inline char16 ToUpperASCII(char16 c) {
   return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
 }
 
-// Function objects to aid in comparing/searching strings.
+// Converts the given string to it's ASCII-lowercase equivalent.
+BASE_EXPORT std::string ToLowerASCII(StringPiece str);
+BASE_EXPORT string16 ToLowerASCII(StringPiece16 str);
 
-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);
-  }
-};
+// Converts the given string to it's ASCII-uppercase equivalent.
+BASE_EXPORT std::string ToUpperASCII(StringPiece str);
+BASE_EXPORT string16 ToUpperASCII(StringPiece16 str);
 
+// Functor for case-insensitive ASCII comparisons for STL algorithms like
+// std::search.
+//
+// Note that a full Unicode version of this functor is not possible to write
+// because case mappings might change the number of characters, depend on
+// context (combining accents), and require handling UTF-16. If you need
+// proper Unicode support, use base::i18n::ToLower/FoldCase and then just
+// use a normal operator== on the result.
 template<typename Char> struct CaseInsensitiveCompareASCII {
  public:
   bool operator()(Char x, Char y) const {
@@ -121,6 +124,22 @@
   }
 };
 
+// Like strcasecmp for case-insensitive ASCII characters only. Returns:
+//   -1  (a < b)
+//    0  (a == b)
+//    1  (a > b)
+// (unlike strcasecmp which can return values greater or less than 1/-1). For
+// full Unicode support, use base::i18n::ToLower or base::i18h::FoldCase
+// and then just call the normal string operators on the result.
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
+// Equality for ASCII case-insensitive comparisons. For full Unicode support,
+// use base::i18n::ToLower or base::i18h::FoldCase and then compare with either
+// == or !=.
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
 // These threadsafe functions return references to globally unique empty
 // strings.
 //
@@ -138,10 +157,12 @@
 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[];
+// encoding. Null-terminated. The ASCII versions are the whitespaces as defined
+// by HTML5, and don't include control characters.
+BASE_EXPORT extern const wchar_t kWhitespaceWide[];  // Includes Unicode.
+BASE_EXPORT extern const char16 kWhitespaceUTF16[];  // Includes Unicode.
 BASE_EXPORT extern const char kWhitespaceASCII[];
+BASE_EXPORT extern const char16 kWhitespaceASCIIAs16[];  // No unicode.
 
 // Null-terminated string representing the UTF-8 byte order mark.
 BASE_EXPORT extern const char kUtf8ByteOrderMark[];
@@ -150,10 +171,10 @@
 // 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,
+                             const StringPiece16& remove_chars,
                              string16* output);
 BASE_EXPORT bool RemoveChars(const std::string& input,
-                             const base::StringPiece& remove_chars,
+                             const StringPiece& remove_chars,
                              std::string* output);
 
 // Replaces characters in |replace_chars| from anywhere in |input| with
@@ -162,49 +183,65 @@
 // |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 StringPiece16& replace_chars,
                               const string16& replace_with,
                               string16* output);
 BASE_EXPORT bool ReplaceChars(const std::string& input,
-                              const base::StringPiece& replace_chars,
+                              const StringPiece& replace_chars,
                               const std::string& replace_with,
                               std::string* output);
 
+enum TrimPositions {
+  TRIM_NONE     = 0,
+  TRIM_LEADING  = 1 << 0,
+  TRIM_TRAILING = 1 << 1,
+  TRIM_ALL      = TRIM_LEADING | TRIM_TRAILING,
+};
+
 // Removes characters in |trim_chars| from the beginning and end of |input|.
-// |trim_chars| must be null-terminated.
-// NOTE: Safe to use the same variable for both |input| and |output|.
+// The 8-bit version only works on 8-bit characters, not UTF-8.
+//
+// It is safe to use the same variable for both |input| and |output| (this is
+// the normal usage to trim in-place).
 BASE_EXPORT bool TrimString(const string16& input,
-                            const base::StringPiece16& trim_chars,
+                            StringPiece16 trim_chars,
                             string16* output);
 BASE_EXPORT bool TrimString(const std::string& input,
-                            const base::StringPiece& trim_chars,
+                            StringPiece trim_chars,
                             std::string* output);
 
+// StringPiece versions of the above. The returned pieces refer to the original
+// buffer.
+BASE_EXPORT StringPiece16 TrimString(StringPiece16 input,
+                                     const StringPiece16& trim_chars,
+                                     TrimPositions positions);
+BASE_EXPORT StringPiece TrimString(StringPiece input,
+                                   const StringPiece& trim_chars,
+                                   TrimPositions positions);
+
 // Truncates a string to the nearest UTF-8 character that will leave
 // the string less than or equal to the specified byte size.
 BASE_EXPORT void TruncateUTF8ToByteSize(const std::string& input,
                                         const size_t byte_size,
                                         std::string* output);
 
-// Trims any whitespace from either end of the input string.  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.
+// Trims any whitespace from either end of the input string.
+//
+// The StringPiece versions return a substring referencing the input buffer.
+// The ASCII versions look only for ASCII whitespace.
+//
+// The std::string versions return where whitespace was found.
 // NOTE: Safe to use the same variable for both input and output.
-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);
+                                         string16* output);
+BASE_EXPORT StringPiece16 TrimWhitespace(StringPiece16 input,
+                                         TrimPositions positions);
 BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
                                               TrimPositions positions,
                                               std::string* output);
+BASE_EXPORT StringPiece TrimWhitespaceASCII(StringPiece input,
+                                            TrimPositions positions);
 
 // Deprecated. This function is only for backward compatibility and calls
 // TrimWhitespaceASCII().
@@ -258,85 +295,43 @@
 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);
-}
+// Compare the lower-case form of the given string against the given
+// previously-lower-cased ASCII string (typically a constant).
+BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece str,
+                                      StringPiece lowecase_ascii);
+BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece16 str,
+                                      StringPiece lowecase_ascii);
 
-template <class str> inline str StringToLowerASCII(const str& s) {
-  // for std::string and std::wstring
-  str output(s);
-  StringToLowerASCII(&output);
-  return output;
-}
+// Performs a case-sensitive string compare of the given 16-bit string against
+// the given 8-bit ASCII string (typically a constant). The behavior is
+// undefined if the |ascii| string is not ASCII.
+BASE_EXPORT bool EqualsASCII(StringPiece16 str, StringPiece ascii);
 
-}  // namespace base
+// Indicates case sensitivity of comparisons. Only ASCII case insensitivity
+// is supported. Full Unicode case-insensitive conversions would need to go in
+// base/i18n so it can use ICU.
+//
+// If you need to do Unicode-aware case-insensitive StartsWith/EndsWith, it's
+// best to call base::i18n::ToLower() or base::i18n::FoldCase() (see
+// base/i18n/case_conversion.h for usage advice) on the arguments, and then use
+// the results to a case-sensitive comparison.
+enum class CompareCase {
+  SENSITIVE,
+  INSENSITIVE_ASCII,
+};
 
-#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);
-
+BASE_EXPORT bool StartsWith(StringPiece str,
+                            StringPiece search_for,
+                            CompareCase case_sensitivity);
+BASE_EXPORT bool StartsWith(StringPiece16 str,
+                            StringPiece16 search_for,
+                            CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece str,
+                          StringPiece search_for,
+                          CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece16 str,
+                          StringPiece16 search_for,
+                          CompareCase case_sensitivity);
 
 // Determines the type of ASCII character, independent of locale (the C
 // library versions will change based on locale).
@@ -360,41 +355,34 @@
          (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 the integer corresponding to the given hex character. For example:
+//    '4' -> 4
+//    'a' -> 10
+//    'B' -> 11
+// Assumes the input is a valid hex character. DCHECKs in debug builds if not.
+BASE_EXPORT char HexDigitToInt(wchar_t c);
 
-// Returns true if it's a whitespace character.
-inline bool IsWhitespace(wchar_t c) {
-  return wcschr(base::kWhitespaceWide, c) != NULL;
-}
+// Returns true if it's a Unicode whitespace character.
+BASE_EXPORT bool IsUnicodeWhitespace(wchar_t c);
 
 // Return a byte string in human-readable format with a unit suffix. Not
 // appropriate for use in any UI; use of FormatBytes and friends in ui/base is
 // highly recommended instead. TODO(avi): Figure out how to get callers to use
 // FormatBytes instead; remove this.
-BASE_EXPORT base::string16 FormatBytesUnlocalized(int64 bytes);
+BASE_EXPORT string16 FormatBytesUnlocalized(int64 bytes);
 
 // Starting at |start_offset| (usually 0), replace the first instance of
 // |find_this| with |replace_with|.
 BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
     base::string16* str,
     size_t start_offset,
-    const base::string16& find_this,
-    const base::string16& replace_with);
+    StringPiece16 find_this,
+    StringPiece16 replace_with);
 BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
     std::string* str,
     size_t start_offset,
-    const std::string& find_this,
-    const std::string& replace_with);
+    StringPiece find_this,
+    StringPiece replace_with);
 
 // Starting at |start_offset| (usually 0), look through |str| and replace all
 // instances of |find_this| with |replace_with|.
@@ -403,14 +391,15 @@
 // characters, for example:
 //   std::replace(str.begin(), str.end(), 'a', 'b');
 BASE_EXPORT void ReplaceSubstringsAfterOffset(
-    base::string16* str,
+    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);
+    StringPiece16 find_this,
+    StringPiece16 replace_with);
+BASE_EXPORT void ReplaceSubstringsAfterOffset(
+    std::string* str,
+    size_t start_offset,
+    StringPiece find_this,
+    StringPiece replace_with);
 
 // Reserves enough memory in |str| to accommodate |length_with_null| characters,
 // sets the size of |str| to |length_with_null - 1| characters, and returns a
@@ -432,101 +421,45 @@
 // 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);
+BASE_EXPORT char* WriteInto(std::string* str, size_t length_with_null);
+BASE_EXPORT char16* WriteInto(string16* str, size_t length_with_null);
+#ifndef OS_WIN
+BASE_EXPORT wchar_t* WriteInto(std::wstring* str, size_t length_with_null);
+#endif
 
 // Does the opposite of SplitString().
-BASE_EXPORT 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);
+BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts,
+                                   StringPiece separator);
+BASE_EXPORT string16 JoinString(const std::vector<string16>& parts,
+                                StringPiece16 separator);
 
 // Replace $1-$2-$3..$9 in the format string with |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,
+BASE_EXPORT string16 ReplaceStringPlaceholders(
+    const string16& format_string,
+    const std::vector<string16>& subst,
     std::vector<size_t>* offsets);
 
 BASE_EXPORT std::string ReplaceStringPlaceholders(
-    const base::StringPiece& format_string,
+    const 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);
+BASE_EXPORT string16 ReplaceStringPlaceholders(const string16& format_string,
+                                               const string16& a,
+                                               size_t* offset);
 
-// Returns true if the string passed in matches the pattern. The pattern
-// string can contain wildcards like * and ?
-// The backslash character (\) is an escape character for * and ?
-// We limit the patterns to having a max of 16 * or ? characters.
-// ? matches 0 or 1 character, while * matches 0 or more characters.
-BASE_EXPORT bool MatchPattern(const base::StringPiece& string,
-                              const base::StringPiece& pattern);
-BASE_EXPORT bool MatchPattern(const base::string16& string,
-                              const base::string16& pattern);
+}  // namespace base
 
-// 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;
+#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
-};
-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
index 146e5fd..aba1b12 100644
--- a/base/strings/string_util_constants.cc
+++ b/base/strings/string_util_constants.cc
@@ -52,6 +52,16 @@
   0
 };
 
+const char16 kWhitespaceASCIIAs16[] = {
+  0x09,    // CHARACTER TABULATION
+  0x0A,    // LINE FEED (LF)
+  0x0B,    // LINE TABULATION
+  0x0C,    // FORM FEED (FF)
+  0x0D,    // CARRIAGE RETURN (CR)
+  0x20,    // SPACE
+  0
+};
+
 const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
 
 }  // namespace base
diff --git a/base/strings/string_util_posix.h b/base/strings/string_util_posix.h
index f4009d4..9e96697 100644
--- a/base/strings/string_util_posix.h
+++ b/base/strings/string_util_posix.h
@@ -20,27 +20,11 @@
   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));
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index d887c0b..765ba83 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -494,8 +494,8 @@
   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 string16_with_nul = ASCIIToUTF16(string_with_nul);
+  EXPECT_EQ(static_cast<string16::size_type>(length_with_nul),
             string16_with_nul.length());
   std::string narrow_with_nul = UTF16ToASCII(string16_with_nul);
   EXPECT_EQ(static_cast<std::string::size_type>(length_with_nul),
@@ -503,30 +503,30 @@
   EXPECT_EQ(0, string_with_nul.compare(narrow_with_nul));
 }
 
+TEST(StringUtilTest, ToLowerASCII) {
+  EXPECT_EQ('c', ToLowerASCII('C'));
+  EXPECT_EQ('c', ToLowerASCII('c'));
+  EXPECT_EQ('2', ToLowerASCII('2'));
+
+  EXPECT_EQ(static_cast<char16>('c'), ToLowerASCII(static_cast<char16>('C')));
+  EXPECT_EQ(static_cast<char16>('c'), ToLowerASCII(static_cast<char16>('c')));
+  EXPECT_EQ(static_cast<char16>('2'), ToLowerASCII(static_cast<char16>('2')));
+
+  EXPECT_EQ("cc2", ToLowerASCII("Cc2"));
+  EXPECT_EQ(ASCIIToUTF16("cc2"), ToLowerASCII(ASCIIToUTF16("Cc2")));
+}
+
 TEST(StringUtilTest, ToUpperASCII) {
   EXPECT_EQ('C', ToUpperASCII('C'));
   EXPECT_EQ('C', ToUpperASCII('c'));
   EXPECT_EQ('2', ToUpperASCII('2'));
 
-  EXPECT_EQ(L'C', ToUpperASCII(L'C'));
-  EXPECT_EQ(L'C', ToUpperASCII(L'c'));
-  EXPECT_EQ(L'2', ToUpperASCII(L'2'));
+  EXPECT_EQ(static_cast<char16>('C'), ToUpperASCII(static_cast<char16>('C')));
+  EXPECT_EQ(static_cast<char16>('C'), ToUpperASCII(static_cast<char16>('c')));
+  EXPECT_EQ(static_cast<char16>('2'), ToUpperASCII(static_cast<char16>('2')));
 
-  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);
+  EXPECT_EQ("CC2", ToUpperASCII("Cc2"));
+  EXPECT_EQ(ASCIIToUTF16("CC2"), ToUpperASCII(ASCIIToUTF16("Cc2")));
 }
 
 TEST(StringUtilTest, LowerCaseEqualsASCII) {
@@ -669,128 +669,7 @@
   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));
@@ -808,8 +687,7 @@
   EXPECT_EQ("a|b|c|| ", JoinString(parts, "|"));
 }
 
-// Test for JoinString overloaded with string16 separator
-TEST(StringUtilTest, JoinStringWithString16) {
+TEST(StringUtilTest, JoinString16) {
   string16 separator = ASCIIToUTF16(", ");
   std::vector<string16> parts;
   EXPECT_EQ(string16(), JoinString(parts, separator));
@@ -828,59 +706,83 @@
 }
 
 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("javascript:url", "javascript",
+                         base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(StartsWith("JavaScript:url", "javascript",
+                          base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(StartsWith("javascript:url", "javascript",
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith("JavaScript:url", "javascript",
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith("java", "javascript", base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(StartsWith("java", "javascript",
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(std::string(), "javascript",
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(std::string(), "javascript",
+                          base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(StartsWith("java", std::string(),
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith("java", std::string(), base::CompareCase::SENSITIVE));
 
   EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
-                         ASCIIToUTF16("javascript"), true));
+                         ASCIIToUTF16("javascript"),
+                         base::CompareCase::SENSITIVE));
   EXPECT_FALSE(StartsWith(ASCIIToUTF16("JavaScript:url"),
-                          ASCIIToUTF16("javascript"), true));
+                          ASCIIToUTF16("javascript"),
+                          base::CompareCase::SENSITIVE));
   EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
-                         ASCIIToUTF16("javascript"), false));
+                         ASCIIToUTF16("javascript"),
+                         base::CompareCase::INSENSITIVE_ASCII));
   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));
+                         ASCIIToUTF16("javascript"),
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"),
+                          base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"),
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"),
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"),
+                          base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(),
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(),
+                         base::CompareCase::SENSITIVE));
 }
 
 TEST(StringUtilTest, EndsWith) {
-  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"),
-                       ASCIIToUTF16(".plugin"), 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));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(
+      EndsWith(string16(), string16(), base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(string16(), string16(), base::CompareCase::SENSITIVE));
 }
 
 TEST(StringUtilTest, GetStringFWithOffsets) {
@@ -994,53 +896,14 @@
             "$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(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
     EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
-    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
   }
 
@@ -1049,10 +912,10 @@
   {
     char dst[2] = {1, 2};
     wchar_t wdst[2] = {1, 2};
-    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", 0));
+    EXPECT_EQ(7U, 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(7U, wcslcpy(wdst, L"abcdefg", 0));
     EXPECT_EQ(static_cast<wchar_t>(1), wdst[0]);
     EXPECT_EQ(static_cast<wchar_t>(2), wdst[1]);
   }
@@ -1061,9 +924,9 @@
   {
     char dst[8];
     wchar_t wdst[8];
-    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
     EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
-    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
   }
 
@@ -1071,9 +934,9 @@
   {
     char dst[7];
     wchar_t wdst[7];
-    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
     EXPECT_EQ(0, memcmp(dst, "abcdef", 7));
-    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"abcdef", sizeof(wchar_t) * 7));
   }
 
@@ -1081,9 +944,9 @@
   {
     char dst[3];
     wchar_t wdst[3];
-    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
     EXPECT_EQ(0, memcmp(dst, "ab", 3));
-    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"ab", sizeof(wchar_t) * 3));
   }
 }
@@ -1116,7 +979,7 @@
     { L"% 10ls", true }
   };
   for (size_t i = 0; i < arraysize(cases); ++i)
-    EXPECT_EQ(cases[i].portable, base::IsWprintfFormatPortable(cases[i].input));
+    EXPECT_EQ(cases[i].portable, IsWprintfFormatPortable(cases[i].input));
 }
 
 TEST(StringUtilTest, RemoveChars) {
@@ -1197,6 +1060,46 @@
                                   kWhitespaceUTF16));
 }
 
+TEST(StringUtilTest, CompareCaseInsensitiveASCII) {
+  EXPECT_EQ(0, CompareCaseInsensitiveASCII("", ""));
+  EXPECT_EQ(0, CompareCaseInsensitiveASCII("Asdf", "aSDf"));
+
+  // Differing lengths.
+  EXPECT_EQ(-1, CompareCaseInsensitiveASCII("Asdf", "aSDfA"));
+  EXPECT_EQ(1, CompareCaseInsensitiveASCII("AsdfA", "aSDf"));
+
+  // Differing values.
+  EXPECT_EQ(-1, CompareCaseInsensitiveASCII("AsdfA", "aSDfb"));
+  EXPECT_EQ(1, CompareCaseInsensitiveASCII("Asdfb", "aSDfA"));
+}
+
+TEST(StringUtilTest, EqualsCaseInsensitiveASCII) {
+  EXPECT_TRUE(EqualsCaseInsensitiveASCII("", ""));
+  EXPECT_TRUE(EqualsCaseInsensitiveASCII("Asdf", "aSDF"));
+  EXPECT_FALSE(EqualsCaseInsensitiveASCII("bsdf", "aSDF"));
+  EXPECT_FALSE(EqualsCaseInsensitiveASCII("Asdf", "aSDFz"));
+}
+
+TEST(StringUtilTest, IsUnicodeWhitespace) {
+  // NOT unicode white space.
+  EXPECT_FALSE(IsUnicodeWhitespace(L'\0'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L'A'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L'0'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L'.'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L';'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L'\x4100'));
+
+  // Actual unicode whitespace.
+  EXPECT_TRUE(IsUnicodeWhitespace(L' '));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\xa0'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\x3000'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\t'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\r'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\v'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\f'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\n'));
+}
+
 class WriteIntoTest : public testing::Test {
  protected:
   static void WritesCorrectly(size_t num_chars) {
diff --git a/base/strings/string_util_win.h b/base/strings/string_util_win.h
index 61eda20..839a799 100644
--- a/base/strings/string_util_win.h
+++ b/base/strings/string_util_win.h
@@ -20,18 +20,6 @@
   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);
diff --git a/base/strings/stringprintf.h b/base/strings/stringprintf.h
index 523f7ee..7a75d89 100644
--- a/base/strings/stringprintf.h
+++ b/base/strings/stringprintf.h
@@ -11,15 +11,18 @@
 
 #include "base/base_export.h"
 #include "base/compiler_specific.h"
+#include "build/build_config.h"
 
 namespace base {
 
 // Return a C++ string given printf-like input.
-BASE_EXPORT std::string StringPrintf(const char* format, ...)
+BASE_EXPORT std::string StringPrintf(_Printf_format_string_ const char* format,
+                                     ...)
     PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
 #if defined(OS_WIN)
-BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
-    WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+BASE_EXPORT std::wstring StringPrintf(
+    _Printf_format_string_ const wchar_t* format,
+    ...) WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
 #endif
 
 // Return a C++ string given vprintf-like input.
@@ -27,21 +30,25 @@
     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);
+BASE_EXPORT const std::string& SStringPrintf(
+    std::string* dst,
+    _Printf_format_string_ const char* format,
+    ...) PRINTF_FORMAT(2, 3);
 #if defined(OS_WIN)
-BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
-                                              const wchar_t* format, ...)
-    WPRINTF_FORMAT(2, 3);
+BASE_EXPORT const std::wstring& SStringPrintf(
+    std::wstring* dst,
+    _Printf_format_string_ const wchar_t* format,
+    ...) WPRINTF_FORMAT(2, 3);
 #endif
 
 // Append result to a supplied string.
-BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
-    PRINTF_FORMAT(2, 3);
+BASE_EXPORT void StringAppendF(std::string* dst,
+                               _Printf_format_string_ const char* format,
+                               ...) PRINTF_FORMAT(2, 3);
 #if defined(OS_WIN)
-BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
-    WPRINTF_FORMAT(2, 3);
+BASE_EXPORT void StringAppendF(std::wstring* dst,
+                               _Printf_format_string_ const wchar_t* format,
+                               ...) WPRINTF_FORMAT(2, 3);
 #endif
 
 // Lower-level routine that takes a va_list and appends to a specified
diff --git a/base/strings/stringprintf_unittest.cc b/base/strings/stringprintf_unittest.cc
index c49637c..e0b320f 100644
--- a/base/strings/stringprintf_unittest.cc
+++ b/base/strings/stringprintf_unittest.cc
@@ -148,10 +148,10 @@
   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.
+// vswprintf in Visual Studio 2013 fails when given U+FFFF. This tests that the
+// failure case is gracefuly handled. In Visual Studio 2015 the bad character
+// is passed through.
 TEST(StringPrintfTest, Invalid) {
   wchar_t invalid[2];
   invalid[0] = 0xffff;
@@ -159,7 +159,11 @@
 
   std::wstring out;
   SStringPrintf(&out, L"%ls", invalid);
+#if _MSC_VER >= 1900
+  EXPECT_STREQ(invalid, out.c_str());
+#else
   EXPECT_STREQ(L"", out.c_str());
+#endif
 }
 #endif
 
diff --git a/base/strings/sys_string_conversions_unittest.cc b/base/strings/sys_string_conversions_unittest.cc
index 0cdd428..90c4767 100644
--- a/base/strings/sys_string_conversions_unittest.cc
+++ b/base/strings/sys_string_conversions_unittest.cc
@@ -76,7 +76,7 @@
 
 TEST(SysStrings, SysWideToNativeMB) {
 #if !defined(SYSTEM_NATIVE_UTF8)
-  ScopedLocale locale("en_US.utf-8");
+  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"));
@@ -108,7 +108,7 @@
 // We assume the test is running in a UTF8 locale.
 TEST(SysStrings, SysNativeMBToWide) {
 #if !defined(SYSTEM_NATIVE_UTF8)
-  ScopedLocale locale("en_US.utf-8");
+  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"));
@@ -164,7 +164,7 @@
 
 TEST(SysStrings, SysNativeMBAndWide) {
 #if !defined(SYSTEM_NATIVE_UTF8)
-  ScopedLocale locale("en_US.utf-8");
+  ScopedLocale locale("en_US.UTF-8");
 #endif
   for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
     std::wstring wide = kConvertRoundtripCases[i];
diff --git a/base/strings/utf_string_conversion_utils.h b/base/strings/utf_string_conversion_utils.h
index 22abbbc..a1b2e64 100644
--- a/base/strings/utf_string_conversion_utils.h
+++ b/base/strings/utf_string_conversion_utils.h
@@ -60,7 +60,6 @@
 
 // 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);
 
diff --git a/base/strings/utf_string_conversions.cc b/base/strings/utf_string_conversions.cc
index 1480d48..b6cf6ff 100644
--- a/base/strings/utf_string_conversions.cc
+++ b/base/strings/utf_string_conversions.cc
@@ -73,7 +73,7 @@
   }
 }
 
-std::wstring UTF8ToWide(const StringPiece& utf8) {
+std::wstring UTF8ToWide(StringPiece utf8) {
   if (IsStringASCII(utf8)) {
     return std::wstring(utf8.begin(), utf8.end());
   }
@@ -153,7 +153,7 @@
   }
 }
 
-string16 UTF8ToUTF16(const StringPiece& utf8) {
+string16 UTF8ToUTF16(StringPiece utf8) {
   if (IsStringASCII(utf8)) {
     return string16(utf8.begin(), utf8.end());
   }
@@ -176,7 +176,7 @@
   }
 }
 
-std::string UTF16ToUTF8(const string16& utf16) {
+std::string UTF16ToUTF8(StringPiece16 utf16) {
   if (IsStringASCII(utf16)) {
     return std::string(utf16.begin(), utf16.end());
   }
@@ -195,7 +195,7 @@
   return UTF8ToWide(src, src_len, output);
 }
 
-string16 UTF8ToUTF16(const StringPiece& utf8) {
+string16 UTF8ToUTF16(StringPiece utf8) {
   return UTF8ToWide(utf8);
 }
 
@@ -203,18 +203,24 @@
   return WideToUTF8(src, src_len, output);
 }
 
-std::string UTF16ToUTF8(const string16& utf16) {
-  return WideToUTF8(utf16);
+std::string UTF16ToUTF8(StringPiece16 utf16) {
+  if (IsStringASCII(utf16))
+    return std::string(utf16.data(), utf16.data() + utf16.length());
+
+  std::string ret;
+  PrepareForUTF8Output(utf16.data(), utf16.length(), &ret);
+  ConvertUnicode(utf16.data(), utf16.length(), &ret);
+  return ret;
 }
 
 #endif
 
-string16 ASCIIToUTF16(const StringPiece& ascii) {
+string16 ASCIIToUTF16(StringPiece ascii) {
   DCHECK(IsStringASCII(ascii)) << ascii;
   return string16(ascii.begin(), ascii.end());
 }
 
-std::string UTF16ToASCII(const string16& utf16) {
+std::string UTF16ToASCII(StringPiece16 utf16) {
   DCHECK(IsStringASCII(utf16)) << UTF16ToUTF8(utf16);
   return std::string(utf16.begin(), utf16.end());
 }
diff --git a/base/strings/utf_string_conversions.h b/base/strings/utf_string_conversions.h
index 06a3bc6..9b15730 100644
--- a/base/strings/utf_string_conversions.h
+++ b/base/strings/utf_string_conversions.h
@@ -24,7 +24,7 @@
 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 std::wstring UTF8ToWide(StringPiece utf8);
 
 BASE_EXPORT bool WideToUTF16(const wchar_t* src, size_t src_len,
                              string16* output);
@@ -34,18 +34,18 @@
 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 string16 UTF8ToUTF16(StringPiece utf8);
 BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
                              std::string* output);
-BASE_EXPORT std::string UTF16ToUTF8(const string16& utf16);
+BASE_EXPORT std::string UTF16ToUTF8(StringPiece16 utf16);
 
 // This converts an ASCII string, typically a hardcoded constant, to a UTF16
 // string.
-BASE_EXPORT string16 ASCIIToUTF16(const StringPiece& ascii);
+BASE_EXPORT string16 ASCIIToUTF16(StringPiece ascii);
 
 // Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
 // beforehand.
-BASE_EXPORT std::string UTF16ToASCII(const string16& utf16);
+BASE_EXPORT std::string UTF16ToASCII(StringPiece16 utf16);
 
 }  // namespace base
 
diff --git a/base/strings/utf_string_conversions_unittest.cc b/base/strings/utf_string_conversions_unittest.cc
index a7b12ff..97d8cbb 100644
--- a/base/strings/utf_string_conversions_unittest.cc
+++ b/base/strings/utf_string_conversions_unittest.cc
@@ -185,11 +185,11 @@
 #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 char16 multi16[] = {
+    'f', 'o', 'o', '\0',
+    'b', 'a', 'r', '\0',
+    'b', 'a', 'z', '\0',
+    '\0'
   };
   static char multi[] = {
     'f', 'o', 'o', '\0',
@@ -197,13 +197,14 @@
     'b', 'a', 'z', '\0',
     '\0'
   };
-  std::wstring wmultistring;
-  memcpy(WriteInto(&wmultistring, arraysize(wmulti)), wmulti, sizeof(wmulti));
-  EXPECT_EQ(arraysize(wmulti) - 1, wmultistring.length());
+  string16 multistring16;
+  memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16,
+                   sizeof(multi16));
+  EXPECT_EQ(arraysize(multi16) - 1, multistring16.length());
   std::string expected;
   memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
   EXPECT_EQ(arraysize(multi) - 1, expected.length());
-  const std::string& converted = WideToUTF8(wmultistring);
+  const std::string& converted = UTF16ToUTF8(multistring16);
   EXPECT_EQ(arraysize(multi) - 1, converted.length());
   EXPECT_EQ(expected, converted);
 }
diff --git a/base/sync_socket.h b/base/sync_socket.h
index 36d6bc1..201fb1c 100644
--- a/base/sync_socket.h
+++ b/base/sync_socket.h
@@ -83,10 +83,8 @@
                                     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();
+  // not block when called.
+  virtual size_t Peek();
 
   // Extracts the contained handle.  Used for transferring between
   // processes.
diff --git a/base/sync_socket_unittest.cc b/base/sync_socket_unittest.cc
index 7c8c97c..0a2f3a7 100644
--- a/base/sync_socket_unittest.cc
+++ b/base/sync_socket_unittest.cc
@@ -49,7 +49,7 @@
 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);
+  static_assert(sizeof(kSending) == sizeof(received), "invalid data size");
 
   ASSERT_EQ(0u, socket_a->Peek());
   ASSERT_EQ(0u, socket_b->Peek());
diff --git a/base/sync_socket_win.cc b/base/sync_socket_win.cc
index e508816..4b5040c 100644
--- a/base/sync_socket_win.cc
+++ b/base/sync_socket_win.cc
@@ -5,6 +5,7 @@
 #include "base/sync_socket.h"
 
 #include "base/logging.h"
+#include "base/rand_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/win/scoped_handle.h"
 
@@ -39,9 +40,8 @@
     flags |= FILE_FLAG_OVERLAPPED;
 
   do {
-    unsigned int rnd_name;
-    if (rand_s(&rnd_name) != 0)
-      return false;
+    unsigned long rnd_name;
+    RandBytes(&rnd_name, sizeof(rnd_name));
 
     swprintf(name, kPipePathMax,
              kPipeNameFormat,
@@ -121,7 +121,7 @@
                                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);
+  static_assert(sizeof(buffer[0]) == sizeof(char), "incorrect buffer type");
   DCHECK_GT(length, 0u);
   DCHECK_LE(length, kMaxMessageLength);
   DCHECK_NE(file, SyncSocket::kInvalidHandle);
diff --git a/base/synchronization/condition_variable.h b/base/synchronization/condition_variable.h
index 5d8507d..91e4d13 100644
--- a/base/synchronization/condition_variable.h
+++ b/base/synchronization/condition_variable.h
@@ -73,6 +73,7 @@
 
 #include "base/base_export.h"
 #include "base/basictypes.h"
+#include "base/logging.h"
 #include "base/synchronization/lock.h"
 
 namespace base {
@@ -104,7 +105,7 @@
 #elif defined(OS_POSIX)
   pthread_cond_t condition_;
   pthread_mutex_t* user_mutex_;
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   base::Lock* user_lock_;     // Needed to adjust shadow lock state on wait.
 #endif
 
diff --git a/base/synchronization/condition_variable_posix.cc b/base/synchronization/condition_variable_posix.cc
index 013284c..0e4668f 100644
--- a/base/synchronization/condition_variable_posix.cc
+++ b/base/synchronization/condition_variable_posix.cc
@@ -7,7 +7,6 @@
 #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"
@@ -16,7 +15,7 @@
 
 ConditionVariable::ConditionVariable(Lock* user_lock)
     : user_mutex_(user_lock->lock_.native_handle())
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
     , user_lock_(user_lock)
 #endif
 {
@@ -42,18 +41,32 @@
 }
 
 ConditionVariable::~ConditionVariable() {
+#if defined(OS_MACOSX)
+  // This hack is necessary to avoid a fatal pthreads subsystem bug in the
+  // Darwin kernel. http://crbug.com/517681.
+  {
+    base::Lock lock;
+    base::AutoLock l(lock);
+    struct timespec ts;
+    ts.tv_sec = 0;
+    ts.tv_nsec = 1;
+    pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(),
+                                       &ts);
+  }
+#endif
+
   int rv = pthread_cond_destroy(&condition_);
   DCHECK_EQ(0, rv);
 }
 
 void ConditionVariable::Wait() {
   base::ThreadRestrictions::AssertWaitAllowed();
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_->CheckHeldAndUnmark();
 #endif
   int rv = pthread_cond_wait(&condition_, user_mutex_);
   DCHECK_EQ(0, rv);
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_->CheckUnheldAndMark();
 #endif
 }
@@ -66,7 +79,7 @@
   relative_time.tv_nsec =
       (usecs % Time::kMicrosecondsPerSecond) * Time::kNanosecondsPerMicrosecond;
 
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_->CheckHeldAndUnmark();
 #endif
 
@@ -104,7 +117,7 @@
 #endif  // OS_MACOSX
 
   DCHECK(rv == 0 || rv == ETIMEDOUT);
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_->CheckUnheldAndMark();
 #endif
 }
diff --git a/base/synchronization/condition_variable_win.cc b/base/synchronization/condition_variable_win.cc
index 5f165c8..4256ac8 100644
--- a/base/synchronization/condition_variable_win.cc
+++ b/base/synchronization/condition_variable_win.cc
@@ -8,7 +8,6 @@
 #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"
@@ -99,7 +98,7 @@
   DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
   CRITICAL_SECTION* cs = user_lock_.lock_.native_handle();
 
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   user_lock_.CheckHeldAndUnmark();
 #endif
 
@@ -205,10 +204,10 @@
 };
 
 WinXPCondVar::WinXPCondVar(Lock* user_lock)
-    : user_lock_(*user_lock),
-      run_state_(RUNNING),
-      allocation_counter_(0),
-      recycling_list_size_(0) {
+    : run_state_(RUNNING),
+      user_lock_(*user_lock),
+      recycling_list_size_(0),
+      allocation_counter_(0) {
   DCHECK(user_lock);
 }
 
diff --git a/base/synchronization/lock.cc b/base/synchronization/lock.cc
index b1576c5..03297ad 100644
--- a/base/synchronization/lock.cc
+++ b/base/synchronization/lock.cc
@@ -6,10 +6,9 @@
 // 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"
+
+#if DCHECK_IS_ON()
 
 namespace base {
 
@@ -36,4 +35,4 @@
 
 }  // namespace base
 
-#endif  // !NDEBUG || DCHECK_ALWAYS_ON
+#endif  // DCHECK_IS_ON()
diff --git a/base/synchronization/lock.h b/base/synchronization/lock.h
index f384e41..81e2748 100644
--- a/base/synchronization/lock.h
+++ b/base/synchronization/lock.h
@@ -6,6 +6,7 @@
 #define BASE_SYNCHRONIZATION_LOCK_H_
 
 #include "base/base_export.h"
+#include "base/logging.h"
 #include "base/synchronization/lock_impl.h"
 #include "base/threading/platform_thread.h"
 
@@ -16,7 +17,7 @@
 // AssertAcquired() method.
 class BASE_EXPORT Lock {
  public:
-#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#if !DCHECK_IS_ON()
    // Optimized wrapper implementation
   Lock() : lock_() {}
   ~Lock() {}
@@ -56,7 +57,7 @@
   }
 
   void AssertAcquired() const;
-#endif  // NDEBUG && !DCHECK_ALWAYS_ON
+#endif  // DCHECK_IS_ON()
 
 #if defined(OS_POSIX)
   // The posix implementation of ConditionVariable needs to be able
@@ -70,7 +71,7 @@
 #endif
 
  private:
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
   // Members and routines taking care of locks assertions.
   // Note that this checks for recursive locks and allows them
   // if the variable is set.  This is allowed by the underlying implementation
@@ -82,7 +83,7 @@
   // 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
+#endif  // DCHECK_IS_ON()
 
   // Platform specific underlying lock implementation.
   internal::LockImpl lock_;
diff --git a/base/synchronization/waitable_event_watcher_win.cc b/base/synchronization/waitable_event_watcher_win.cc
index 46d47ac..6533539 100644
--- a/base/synchronization/waitable_event_watcher_win.cc
+++ b/base/synchronization/waitable_event_watcher_win.cc
@@ -22,7 +22,7 @@
     const EventCallback& callback) {
   callback_ = callback;
   event_ = event;
-  return watcher_.StartWatching(event->handle(), this);
+  return watcher_.StartWatchingOnce(event->handle(), this);
 }
 
 void WaitableEventWatcher::StopWatching() {
diff --git a/base/synchronization/waitable_event_win.cc b/base/synchronization/waitable_event_win.cc
index 4db5627..2d6d734 100644
--- a/base/synchronization/waitable_event_win.cc
+++ b/base/synchronization/waitable_event_win.cc
@@ -73,7 +73,7 @@
 size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) {
   base::ThreadRestrictions::AssertWaitAllowed();
   HANDLE handles[MAXIMUM_WAIT_OBJECTS];
-  CHECK_LE(count, MAXIMUM_WAIT_OBJECTS)
+  CHECK_LE(count, static_cast<size_t>(MAXIMUM_WAIT_OBJECTS))
       << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany";
 
   for (size_t i = 0; i < count; ++i)
diff --git a/base/sys_byteorder.h b/base/sys_byteorder.h
index 704ed56..efdf7df 100644
--- a/base/sys_byteorder.h
+++ b/base/sys_byteorder.h
@@ -14,12 +14,6 @@
 #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.
diff --git a/base/sys_info.cc b/base/sys_info.cc
index 8640dc1..ebc2a2e 100644
--- a/base/sys_info.cc
+++ b/base/sys_info.cc
@@ -41,26 +41,26 @@
 
   // Low End Device Mode will be enabled if this client is assigned to
   // one of those EnabledXXX groups.
-  if (StartsWithASCII(group_name, "Enabled", true))
+  if (StartsWith(group_name, "Enabled", CompareCase::SENSITIVE))
     return true;
 
   return g_lazy_low_end_device.Get().value();
 }
 #endif
 
-#if !defined(OS_MACOSX) || defined(OS_IOS)
+#if (!defined(OS_MACOSX) || defined(OS_IOS)) && !defined(OS_ANDROID)
 std::string SysInfo::HardwareModelName() {
   return std::string();
 }
 #endif
 
 // static
-int64 SysInfo::Uptime() {
+base::TimeDelta SysInfo::Uptime() {
   // This code relies on an implementation detail of TimeTicks::Now() - that
   // its return value happens to coincide with the system uptime value in
   // microseconds, on Win/Mac/iOS/Linux/ChromeOS and Android.
   int64 uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
-  return uptime_in_microseconds / 1000;
+  return base::TimeDelta::FromMicroseconds(uptime_in_microseconds);
 }
 
 }  // namespace base
diff --git a/base/sys_info.h b/base/sys_info.h
index 654d694..67200ae 100644
--- a/base/sys_info.h
+++ b/base/sys_info.h
@@ -48,13 +48,13 @@
   // or -1 on failure.
   static int64 AmountOfFreeDiskSpace(const FilePath& path);
 
-  // Returns system uptime in milliseconds.
-  static int64 Uptime();
+  // Returns system uptime.
+  static TimeDelta 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.
+  // string if the machine model is unknown or an error occured.
+  // e.g. "MacPro1,1" on Mac, or "Nexus 5" on Android. Only implemented on OS X,
+  // Android, and Chrome OS. This returns an empty string on other platforms.
   static std::string HardwareModelName();
 
   // Returns the name of the host operating system.
@@ -129,9 +129,6 @@
   // 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)
diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc
index 245097f..0eeb581 100644
--- a/base/sys_info_android.cc
+++ b/base/sys_info_android.cc
@@ -59,8 +59,8 @@
 // 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 kDefaultAndroidMajorVersion = 6;
+const int kDefaultAndroidMinorVersion = 0;
 const int kDefaultAndroidBugfixVersion = 99;
 
 // Parse out the OS version numbers from the system properties.
@@ -155,28 +155,16 @@
 
 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() {
+std::string SysInfo::HardwareModelName() {
   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::OperatingSystemName() {
+  return "Android";
+}
+
 std::string SysInfo::OperatingSystemVersion() {
   int32 major, minor, bugfix;
   OperatingSystemVersionNumbers(&major, &minor, &bugfix);
@@ -195,6 +183,18 @@
                         bugfix_version);
 }
 
+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);
+}
+
 int SysInfo::DalvikHeapSizeMB() {
   static int heap_size = GetDalvikHeapSizeMB();
   return heap_size;
diff --git a/base/sys_info_ios.mm b/base/sys_info_ios.mm
index 49d618c..5aa3180 100644
--- a/base/sys_info_ios.mm
+++ b/base/sys_info_ios.mm
@@ -4,10 +4,10 @@
 
 #include "base/sys_info.h"
 
-#import <UIKit/UIKit.h>
 #include <mach/mach.h>
 #include <sys/sysctl.h>
 #include <sys/types.h>
+#import <UIKit/UIKit.h>
 
 #include "base/logging.h"
 #include "base/mac/scoped_mach_port.h"
@@ -66,7 +66,7 @@
   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,
+  int result = host_info(host.get(),
                          HOST_BASIC_INFO,
                          reinterpret_cast<host_info_t>(&hostinfo),
                          &count);
diff --git a/base/sys_info_mac.cc b/base/sys_info_mac.cc
index 18df624..025c768 100644
--- a/base/sys_info_mac.cc
+++ b/base/sys_info_mac.cc
@@ -46,7 +46,7 @@
   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,
+  int result = host_info(host.get(),
                          HOST_BASIC_INFO,
                          reinterpret_cast<host_info_t>(&hostinfo),
                          &count);
diff --git a/base/sys_info_unittest.cc b/base/sys_info_unittest.cc
index 15ae098..127d930 100644
--- a/base/sys_info_unittest.cc
+++ b/base/sys_info_unittest.cc
@@ -56,13 +56,13 @@
 #endif
 
 TEST_F(SysInfoTest, Uptime) {
-  int64 up_time_1 = base::SysInfo::Uptime();
+  base::TimeDelta up_time_1 = base::SysInfo::Uptime();
   // UpTime() is implemented internally using TimeTicks::Now(), which documents
   // system resolution as being 1-15ms. Sleep a little longer than that.
   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
-  int64 up_time_2 = base::SysInfo::Uptime();
-  EXPECT_GT(up_time_1, 0);
-  EXPECT_GT(up_time_2, up_time_1);
+  base::TimeDelta up_time_2 = base::SysInfo::Uptime();
+  EXPECT_GT(up_time_1.InMicroseconds(), 0);
+  EXPECT_GT(up_time_2.InMicroseconds(), up_time_1.InMicroseconds());
 }
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc
index c8314c7..4eccbd7 100644
--- a/base/sys_info_win.cc
+++ b/base/sys_info_win.cc
@@ -48,7 +48,7 @@
 
 // static
 int64 SysInfo::AmountOfVirtualMemory() {
-  return 0;
+  return AmountOfMemory(&MEMORYSTATUSEX::ullTotalVirtual);
 }
 
 // static
diff --git a/base/task_runner.h b/base/task_runner.h
index 7d07b8c..6369c4f 100644
--- a/base/task_runner.h
+++ b/base/task_runner.h
@@ -104,7 +104,7 @@
   //  public:
   //    void GetData() {
   //      scoped_refptr<DataBuffer> buffer = new DataBuffer();
-  //      target_thread_.message_loop_proxy()->PostTaskAndReply(
+  //      target_thread_.task_runner()->PostTaskAndReply(
   //          FROM_HERE,
   //          base::Bind(&DataBuffer::AddData, buffer),
   //          base::Bind(&DataLoader::OnDataReceived, AsWeakPtr(), buffer));
diff --git a/base/task_runner_util.h b/base/task_runner_util.h
index b6dd0f3..da088db 100644
--- a/base/task_runner_util.h
+++ b/base/task_runner_util.h
@@ -47,7 +47,7 @@
 // PostTaskAndReplyWithResult as in this example:
 //
 // PostTaskAndReplyWithResult(
-//     target_thread_.message_loop_proxy(),
+//     target_thread_.task_runner(),
 //     FROM_HERE,
 //     Bind(&DoWorkAndReturn),
 //     Bind(&Callback));
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
index 8245cfc..0a4f22e 100644
--- a/base/task_runner_util_unittest.cc
+++ b/base/task_runner_util_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "base/task_runner_util.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/run_loop.h"
@@ -40,7 +42,7 @@
 
 void ExpectFoo(scoped_ptr<Foo> foo) {
   EXPECT_TRUE(foo.get());
-  scoped_ptr<Foo> local_foo(foo.Pass());
+  scoped_ptr<Foo> local_foo(std::move(foo));
   EXPECT_TRUE(local_foo.get());
   EXPECT_FALSE(foo.get());
 }
@@ -58,7 +60,7 @@
 
 void ExpectScopedFoo(scoped_ptr<Foo, FooDeleter> foo) {
   EXPECT_TRUE(foo.get());
-  scoped_ptr<Foo, FooDeleter> local_foo(foo.Pass());
+  scoped_ptr<Foo, FooDeleter> local_foo(std::move(foo));
   EXPECT_TRUE(local_foo.get());
   EXPECT_FALSE(foo.get());
 }
diff --git a/base/template_util.h b/base/template_util.h
index 83fa322..6d4ac9f 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -117,12 +117,6 @@
                             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
index 3ec3887..32883f2 100644
--- a/base/template_util_unittest.cc
+++ b/base/template_util_unittest.cc
@@ -18,23 +18,24 @@
 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);
+static_assert(!is_pointer<int>::value, "IsPointer");
+static_assert(!is_pointer<int&>::value, "IsPointer");
+static_assert(is_pointer<int*>::value, "IsPointer");
+static_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);
+static_assert(!is_array<int>::value, "IsArray");
+static_assert(!is_array<int*>::value, "IsArray");
+static_assert(!is_array<int (*)[3]>::value, "IsArray");
+static_assert(is_array<int[]>::value, "IsArray");
+static_assert(is_array<const int[]>::value, "IsArray");
+static_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);
+static_assert(!is_non_const_reference<int>::value, "IsNonConstReference");
+static_assert(!is_non_const_reference<const int&>::value,
+              "IsNonConstReference");
+static_assert(is_non_const_reference<int&>::value, "IsNonConstReference");
 
 // is_convertible<From, To>
 
@@ -44,66 +45,64 @@
 //     (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);
+static_assert((is_convertible<Child, Parent>::value), "IsConvertible");
+static_assert(!(is_convertible<Parent, Child>::value), "IsConvertible");
+static_assert(!(is_convertible<Parent, AStruct>::value), "IsConvertible");
+static_assert((is_convertible<int, double>::value), "IsConvertible");
+static_assert((is_convertible<int*, void*>::value), "IsConvertible");
+static_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);
+static_assert(!(is_convertible<int[10], double>::value), "IsConvertible");
+static_assert(!(is_convertible<double, int[10]>::value), "IsConvertible");
+static_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);
-
+static_assert(!(is_same<Child, Parent>::value), "IsSame");
+static_assert(!(is_same<Parent, Child>::value), "IsSame");
+static_assert((is_same<Parent, Parent>::value), "IsSame");
+static_assert((is_same<int*, int*>::value), "IsSame");
+static_assert((is_same<int, int>::value), "IsSame");
+static_assert((is_same<void, void>::value), "IsSame");
+static_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);
+static_assert(is_class<AStruct>::value, "IsClass");
+static_assert(is_class<AClass>::value, "IsClass");
+static_assert(!is_class<AnEnum>::value, "IsClass");
+static_assert(!is_class<int>::value, "IsClass");
+static_assert(!is_class<char*>::value, "IsClass");
+static_assert(!is_class<int&>::value, "IsClass");
+static_assert(!is_class<char[3]>::value, "IsClass");
 
+static_assert(!is_member_function_pointer<int>::value,
+              "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<int*>::value,
+              "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<void*>::value,
+              "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<AStruct>::value,
+              "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<AStruct*>::value,
+              "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<void (*)()>::value,
+              "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<int (*)(int)>::value,
+              "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<int (*)(int, int)>::value,
+              "IsMemberFunctionPointer");
 
-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);
+static_assert(is_member_function_pointer<void (AStruct::*)()>::value,
+              "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<void (AStruct::*)(int)>::value,
+              "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<int (AStruct::*)(int)>::value,
+              "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<int (AStruct::*)(int) const>::value,
+              "IsMemberFunctionPointer");
+static_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
index 91456db..4c9b784 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -27,25 +27,20 @@
   # TODO http://crbug.com/412064 enable this flag all the time.
   testonly = !is_component_build
   sources = [
-    "expectations/expectation.cc",
-    "expectations/expectation.h",
-    "expectations/parser.cc",
-    "expectations/parser.h",
     "gtest_util.cc",
     "gtest_util.h",
+    "gtest_xml_unittest_result_printer.cc",
+    "gtest_xml_unittest_result_printer.h",
     "gtest_xml_util.cc",
     "gtest_xml_util.h",
     "histogram_tester.cc",
     "histogram_tester.h",
-    "launcher/test_launcher.cc",
-    "launcher/test_launcher.h",
+    "ios/wait_util.h",
+    "ios/wait_util.mm",
     "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",
@@ -54,9 +49,7 @@
     "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",
@@ -112,6 +105,8 @@
     "test_support_android.h",
     "test_support_ios.h",
     "test_support_ios.mm",
+    "test_ui_thread_android.cc",
+    "test_ui_thread_android.h",
     "thread_test_helper.cc",
     "thread_test_helper.h",
     "trace_event_analyzer.cc",
@@ -124,18 +119,39 @@
     "values_test_util.h",
   ]
 
+  if (is_ios) {
+    sources += [ "launcher/unit_test_launcher_ios.cc" ]
+  } else {
+    sources += [
+      "launcher/test_launcher.cc",
+      "launcher/test_launcher.h",
+      "launcher/test_results_tracker.cc",
+      "launcher/unit_test_launcher.cc",
+      "multiprocess_test.cc",
+      "multiprocess_test_android.cc",
+    ]
+  }
+
+  configs += [ "//build/config:precompiled_headers" ]
+
+  data = [
+    # The isolate needs this script for setting up the test. It's not actually
+    # needed to run this target locally.
+    "//testing/test_env.py",
+  ]
+
   public_deps = [
     ":test_config",
     "//base",
-    "//base:i18n",
     "//base:base_static",
+    "//base:i18n",
   ]
   deps = [
     "//base/third_party/dynamic_annotations",
     "//testing/gmock",
     "//testing/gtest",
-    "//third_party/libxml",
     "//third_party/icu:icuuc",
+    "//third_party/libxml",
   ]
 
   if (!is_posix) {
@@ -144,14 +160,11 @@
       "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).
+  if (is_ios) {
     set_sources_assignment_filter([])
     sources += [ "test_file_util_mac.cc" ]
+    set_sources_assignment_filter(sources_assignment_filter)
   }
 
   if (is_android) {
@@ -195,6 +208,7 @@
     ]
     deps = [
       "//base",
+      "//build/config/sanitizers:deps",
     ]
   }
 }
@@ -203,6 +217,7 @@
   generate_jni("base_unittests_jni_headers") {
     sources = [
       "android/java/src/org/chromium/base/ContentUriTestUtils.java",
+      "android/java/src/org/chromium/base/TestUiThread.java",
     ]
     jni_package = "base"
   }
diff --git a/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java b/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java
index 4a1613b..f6d5f60 100644
--- a/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java
+++ b/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java
@@ -10,6 +10,8 @@
 import android.net.Uri;
 import android.provider.MediaStore;
 
+import org.chromium.base.annotations.CalledByNative;
+
 /**
  * Utilities for testing operations on content URI.
  */
diff --git a/base/test/android/java/src/org/chromium/base/TestUiThread.java b/base/test/android/java/src/org/chromium/base/TestUiThread.java
new file mode 100644
index 0000000..237c0ec
--- /dev/null
+++ b/base/test/android/java/src/org/chromium/base/TestUiThread.java
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Looper;
+
+import org.chromium.base.annotations.CalledByNative;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * Set up a thread as the Chromium UI Thread, and run its looper. This is is intended for C++ unit
+ * tests (e.g. the net unit tests) that don't run with the UI thread as their main looper, but test
+ * code that, on Android, uses UI thread events, so need a running UI thread.
+ */
+@ThreadSafe
+public class TestUiThread {
+    private static final AtomicBoolean sStarted = new AtomicBoolean(false);
+    private static final String TAG = "cr.TestUiThread";
+
+    @CalledByNative
+    private static void loop() {
+        // @{link ThreadUtils#setUiThread(Looper)} can only be called once in a test run, so do this
+        // once, and leave it running.
+        if (sStarted.getAndSet(true)) return;
+
+        final CountDownLatch startLatch = new CountDownLatch(1);
+        new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                Looper.prepare();
+                ThreadUtils.setUiThread(Looper.myLooper());
+                startLatch.countDown();
+                Looper.loop();
+            }
+
+        }).start();
+
+        try {
+            startLatch.await();
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Failed to set UI Thread");
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
index 53dee4a..7937284 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
@@ -5,21 +5,15 @@
 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 org.chromium.base.test.util.parameter.BaseParameter;
+import org.chromium.base.test.util.parameter.Parameter;
+import org.chromium.base.test.util.parameter.Parameterizable;
+import org.chromium.base.test.util.parameter.parameters.MethodParameter;
 
-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;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Base class for all Activity-based Instrumentation tests.
@@ -27,12 +21,9 @@
  * @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
+        extends ActivityInstrumentationTestCase2<T> implements Parameterizable {
+    private Parameter.Reader mParameterReader;
+    private Map<String, BaseParameter> mAvailableParameters;
 
     /**
      * Creates a instance for running tests against an Activity of the given class.
@@ -44,75 +35,55 @@
     }
 
     /**
-     * Sets up the CommandLine with the appropriate flags.
+     * Creates the {@link Map} of available parameters for the test to use.
      *
-     * 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.
+     * @return a {@link Map} of {@link BaseParameter} objects.
      */
-    @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);
-        }
+    protected Map<String, BaseParameter> createAvailableParameters() {
+        Map<String, BaseParameter> availableParameters = new HashMap<>();
+        availableParameters
+                .put(MethodParameter.PARAMETER_TAG, new MethodParameter(getParameterReader()));
+        return availableParameters;
     }
 
     /**
-     * Gets the target context.
+     * Gets the {@link Map} of available parameters that inherited classes can use.
      *
-     * 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.
+     * @return a {@link Map} of {@link BaseParameter} objects to set as the available parameters.
      */
-    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;
+    public Map<String, BaseParameter> getAvailableParameters() {
+        return mAvailableParameters;
     }
 
-    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);
+    /**
+     * Gets a specific parameter from the current test.
+     *
+     * @param parameterTag a string with the name of the {@link BaseParameter} we want.
+     * @return a parameter that extends {@link BaseParameter} that has the matching parameterTag.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends BaseParameter> T getAvailableParameter(String parameterTag) {
+        return (T) mAvailableParameters.get(parameterTag);
+    }
 
-        if (element.isAnnotationPresent(CommandLineFlags.Add.class)) {
-            flags.addAll(
-                    Arrays.asList(element.getAnnotation(CommandLineFlags.Add.class).value()));
-        }
+    /**
+     * Setter method for {@link Parameter.Reader}.
+     *
+     * @param parameterReader the {@link Parameter.Reader} to set.
+     */
+    public void setParameterReader(Parameter.Reader parameterReader) {
+        mParameterReader = parameterReader;
+        mAvailableParameters = createAvailableParameters();
+    }
 
-        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;
+    /**
+     * Getter method for {@link Parameter.Reader} object to be used by test cases reading the
+     * parameter.
+     *
+     * @return the {@link Parameter.Reader} for the current {@link
+     * org.chromium.base.test.util.parameter.ParameterizedTest} being run.
+     */
+    protected Parameter.Reader getParameterReader() {
+        return mParameterReader;
     }
 }
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
index 8a3395a..58e5b1c 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -4,88 +4,40 @@
 
 package org.chromium.base.test;
 
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 import android.os.Build;
 import android.os.Bundle;
 import android.test.AndroidTestRunner;
 import android.test.InstrumentationTestRunner;
-import android.util.Log;
+import android.text.TextUtils;
 
 import junit.framework.TestCase;
 import junit.framework.TestResult;
 
+import org.chromium.base.Log;
+import org.chromium.base.SysUtils;
+import org.chromium.base.multidex.ChromiumMultiDex;
+import org.chromium.base.test.BaseTestResult.SkipCheck;
+import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.base.test.util.Restriction;
 import org.chromium.test.reporter.TestStatusListener;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.lang.reflect.Method;
 
 // 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 = "base_test";
 
-    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
+    public void onCreate(Bundle arguments) {
+        ChromiumMultiDex.install(getTargetContext());
+        super.onCreate(arguments);
     }
 
     @Override
@@ -93,8 +45,8 @@
         AndroidTestRunner runner = new AndroidTestRunner() {
             @Override
             protected TestResult createTestResult() {
-                SkippingTestResult r = new SkippingTestResult();
-                r.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
+                BaseTestResult r = new BaseTestResult(BaseInstrumentationTestRunner.this);
+                addTestHooks(r);
                 return r;
             }
         };
@@ -103,12 +55,75 @@
     }
 
     /**
+     * Override this method to register hooks and checks to be run for each test. Make sure to call
+     * the base implementation if you do so.
+     *
+     * @see BaseTestResult#addSkipCheck(BaseTestResult.SkipCheck)
+     * @see BaseTestResult#addPreTestHook(BaseTestResult.PreTestHook)
+     */
+    protected void addTestHooks(BaseTestResult result) {
+        result.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
+        result.addSkipCheck(new RestrictionSkipCheck());
+
+        result.addPreTestHook(CommandLineFlags.getRegistrationHook());
+    }
+
+    /**
+     * Checks if any restrictions exist and skip the test if it meets those restrictions.
+     */
+    public class RestrictionSkipCheck implements SkipCheck {
+        @Override
+        public boolean shouldSkip(TestCase testCase) {
+            Method method;
+            try {
+                method = testCase.getClass().getMethod(testCase.getName(), (Class[]) null);
+            } catch (NoSuchMethodException e) {
+                Log.e(TAG, "Unable to find %s in %s", testCase.getName(),
+                        testCase.getClass().getName(), e);
+                return true;
+            }
+            Restriction restrictions = method.getAnnotation(Restriction.class);
+            if (restrictions != null) {
+                for (String restriction : restrictions.value()) {
+                    if (restrictionApplies(restriction)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        protected boolean restrictionApplies(String restriction) {
+            if (TextUtils.equals(restriction, Restriction.RESTRICTION_TYPE_LOW_END_DEVICE)
+                    && !SysUtils.isLowEndDevice()) {
+                return true;
+            }
+            if (TextUtils.equals(restriction, Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE)
+                    && SysUtils.isLowEndDevice()) {
+                return true;
+            }
+            if (TextUtils.equals(restriction, Restriction.RESTRICTION_TYPE_INTERNET)
+                    && !isNetworkAvailable()) {
+                return true;
+            }
+            return false;
+        }
+
+        private boolean isNetworkAvailable() {
+            final ConnectivityManager connectivityManager = (ConnectivityManager)
+                    getTargetContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+            final NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
+            return activeNetworkInfo != null && activeNetworkInfo.isConnected();
+        }
+    }
+
+    /**
      * 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
+         * If {@link MinAndroidSdkLevel} is present, checks its value
          * against the device's SDK level.
          *
          * @param testCase The test to check.
@@ -129,5 +144,4 @@
             return false;
         }
     }
-
 }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java b/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java
new file mode 100644
index 0000000..7ac4bee
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java
@@ -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.
+
+package org.chromium.base.test;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.SystemClock;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+import org.chromium.base.Log;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.parameter.BaseParameter;
+import org.chromium.base.test.util.parameter.Parameter;
+import org.chromium.base.test.util.parameter.Parameterizable;
+import org.chromium.base.test.util.parameter.ParameterizedTest;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * A test result that can skip tests.
+ */
+public class BaseTestResult extends TestResult {
+    private static final String TAG = "base_test";
+
+    private static final int SLEEP_INTERVAL_MS = 50;
+    private static final int WAIT_DURATION_MS = 5000;
+
+    private final Instrumentation mInstrumentation;
+    private final List<SkipCheck> mSkipChecks;
+    private final List<PreTestHook> mPreTestHooks;
+
+    /**
+     * Creates an instance of BaseTestResult.
+     */
+    public BaseTestResult(Instrumentation instrumentation) {
+        mSkipChecks = new ArrayList<>();
+        mPreTestHooks = new ArrayList<>();
+        mInstrumentation = instrumentation;
+    }
+
+    /**
+     * 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.
+         */
+        boolean shouldSkip(TestCase testCase);
+    }
+
+    /**
+     * An interface for classes that have some code to run before a test. They run after
+     * {@link SkipCheck}s. Provides access to the test method (and the annotations defined for it)
+     * and the instrumentation context.
+     */
+    public interface PreTestHook {
+        /**
+         * @param targetContext the instrumentation context that will be used during the test.
+         * @param testMethod the test method to be run.
+         */
+        public void run(Context targetContext, Method testMethod);
+    }
+
+    /**
+     * Adds a check for whether a test should run.
+     *
+     * @param skipCheck The check to add.
+     */
+    public void addSkipCheck(SkipCheck skipCheck) {
+        mSkipChecks.add(skipCheck);
+    }
+
+    /**
+     * Adds hooks that will be executed before each test that runs.
+     *
+     * @param preTestHook The hook to add.
+     */
+    public void addPreTestHook(PreTestHook preTestHook) {
+        mPreTestHooks.add(preTestHook);
+    }
+
+    protected boolean shouldSkip(TestCase test) {
+        for (SkipCheck s : mSkipChecks) {
+            if (s.shouldSkip(test)) return true;
+        }
+        return false;
+    }
+
+    private void runPreTestHooks(TestCase test) {
+        try {
+            Method testMethod = test.getClass().getMethod(test.getName());
+            Context targetContext = getTargetContext();
+
+            for (PreTestHook hook : mPreTestHooks) {
+                hook.run(targetContext, testMethod);
+            }
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "Unable to run pre test hooks.", e);
+        }
+    }
+
+    @Override
+    protected void run(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);
+            mInstrumentation.sendStatus(0, skipResult);
+
+            endTest(test);
+        } else {
+            runPreTestHooks(test);
+
+            if (test instanceof Parameterizable) {
+                try {
+                    runParameterized(test);
+                } catch (ThreadDeath e) {
+                    Log.e(TAG, "Parameterized test run failed: %s", e);
+                }
+            } else {
+                super.run(test);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends TestCase & Parameterizable> void runParameterized(TestCase test)
+            throws ThreadDeath {
+        T testCase = (T) test;
+
+        // Prepare test.
+        Parameter.Reader parameterReader = new Parameter.Reader(test);
+        testCase.setParameterReader(parameterReader);
+        List<ParameterizedTest> parameterizedTests = parameterReader.getParameterizedTests();
+        List<ParameterError> errors = new ArrayList<>();
+        List<ParameterError> failures = new ArrayList<>();
+        Map<String, BaseParameter> availableParameters = testCase.getAvailableParameters();
+
+        // Remove all @ParameterizedTests that contain CommandLineFlags.Parameter -- those
+        // are handled in test_runner.py as it is needed to re-launch the whole test activity
+        // to apply command-line args correctly. Note that this way we will also ignore any
+        // other parameters that may present in these @ParameterizedTests.
+        for (Iterator<ParameterizedTest> iter = parameterizedTests.iterator(); iter.hasNext();) {
+            ParameterizedTest paramTest = iter.next();
+            for (Parameter p: paramTest.parameters()) {
+                if (CommandLineFlags.Parameter.PARAMETER_TAG.equals(p.tag())) {
+                    iter.remove();
+                }
+            }
+        }
+
+        if (parameterizedTests.isEmpty()) {
+            super.run(test);
+        } else {
+            // Start test.
+            startTest(testCase);
+            for (ParameterizedTest parameterizedTest : parameterizedTests) {
+                parameterReader.setCurrentParameterizedTest(parameterizedTest);
+                try {
+                    setUpParameters(availableParameters, parameterReader);
+                    testCase.runBare();
+                    tearDownParameters(availableParameters, parameterReader);
+                } catch (AssertionFailedError e) {
+                    failures.add(new ParameterError(e, parameterizedTest));
+                } catch (ThreadDeath e) {
+                    throw e;
+                } catch (Throwable e) {
+                    errors.add(new ParameterError(e, parameterizedTest));
+                }
+            }
+
+            // Generate failures and errors.
+            if (!failures.isEmpty()) {
+                addFailure(test, new ParameterizedTestFailure(failures));
+            }
+            if (!errors.isEmpty()) {
+                addError(test, new ParameterizedTestError(errors));
+            }
+
+            // End test.
+            endTest(testCase);
+        }
+    }
+
+    private static <T extends TestCase & Parameterizable> void setUpParameters(
+            Map<String, BaseParameter> availableParameters, Parameter.Reader reader)
+            throws Exception {
+        for (Entry<String, BaseParameter> entry : availableParameters.entrySet()) {
+            if (reader.getParameter(entry.getValue().getTag()) != null) {
+                entry.getValue().setUp();
+            }
+        }
+    }
+
+    private static <T extends TestCase & Parameterizable> void tearDownParameters(
+            Map<String, BaseParameter> availableParameters, Parameter.Reader reader)
+            throws Exception {
+        for (Entry<String, BaseParameter> entry : availableParameters.entrySet()) {
+            if (reader.getParameter(entry.getValue().getTag()) != null) {
+                entry.getValue().tearDown();
+            }
+        }
+    }
+
+    private static class ParameterError {
+        private final Throwable mThrowable;
+        private final ParameterizedTest mParameterizedTest;
+
+        public ParameterError(Throwable throwable, ParameterizedTest parameterizedTest) {
+            mThrowable = throwable;
+            mParameterizedTest = parameterizedTest;
+        }
+
+        private Throwable getThrowable() {
+            return mThrowable;
+        }
+
+        private ParameterizedTest getParameterizedTest() {
+            return mParameterizedTest;
+        }
+    }
+
+    private static class ParameterizedTestFailure extends AssertionFailedError {
+        public ParameterizedTestFailure(List<ParameterError> failures) {
+            super(new ParameterizedTestError(failures).toString());
+        }
+    }
+
+    private static class ParameterizedTestError extends Exception {
+        private final List<ParameterError> mErrors;
+
+        public ParameterizedTestError(List<ParameterError> errors) {
+            mErrors = errors;
+        }
+
+        /**
+         * Error output is as follows.
+         *
+         * DEFINITIONS:
+         * {{ERROR}} is the standard error output from
+         * {@link ParameterError#getThrowable().toString()}.
+         * {{PARAMETER_TAG}} is the {@link Parameter#tag()} value associated with the parameter.
+         * {{ARGUMENT_NAME}} is the {@link Parameter.Argument#name()} associated with the argument.
+         * {{ARGUMENT_VALUE}} is the value associated with the {@link Parameter.Argument}. This can
+         * be a String, int, String[], or int[].
+         *
+         * With no {@link Parameter}:
+         * {{ERROR}} (with no parameters)
+         *
+         * With Single {@link Parameter} and no {@link Parameter.Argument}:
+         * {{ERROR}} (with parameters: {{PARAMETER_TAG}} with no arguments)
+         *
+         * With Single {@link Parameter} and one {@link Parameter.Argument}:
+         * {{ERROR}} (with parameters: {{PARAMETER_TAG}} with arguments:
+         * {{ARGUMENT_NAME}}={{ARGUMENT_VALUE}})
+         *
+         * With Single {@link Parameter} and multiple {@link Parameter.Argument}s:
+         * {{ERROR}} (with parameters: {{PARAMETER_TAG}} with arguments:
+         * {{ARGUMENT_NAME}}={{ARGUMENT_VALUE}}, {{ARGUMENT_NAME}}={{ARGUMENT_VALUE}}, ...)
+         *
+         * DEFINITION:
+         * {{PARAMETER_ERROR}} is the output of a single {@link Parameter}'s error. Format:
+         * {{PARAMETER_TAG}} with arguments: {{ARGUMENT_NAME}}={{ARGUMENT_NAME}}, ...
+         *
+         * With Multiple {@link Parameter}s:
+         * {{ERROR}} (with parameters: {{PARAMETER_ERROR}}; {{PARAMETER_ERROR}}; ...)
+         *
+         * There will be a trace after this. And this is shown for every possible {@link
+         * ParameterizedTest} that is failed in the {@link ParameterizedTest.Set} if there is one.
+         *
+         * @return the error message and trace of the test failures.
+         */
+        @Override
+        public String toString() {
+            if (mErrors.isEmpty()) return "\n";
+            StringBuilder builder = new StringBuilder();
+            Iterator<ParameterError> iter = mErrors.iterator();
+            if (iter.hasNext()) {
+                builder.append(createErrorBuilder(iter.next()));
+            }
+            while (iter.hasNext()) {
+                builder.append("\n").append(createErrorBuilder(iter.next()));
+            }
+            return builder.toString();
+        }
+
+        private static StringBuilder createErrorBuilder(ParameterError error) {
+            StringBuilder builder = new StringBuilder("\n").append(error.getThrowable().toString());
+            List<Parameter> parameters =
+                    Arrays.asList(error.getParameterizedTest().parameters());
+            if (parameters.isEmpty()) {
+                builder.append(" (with no parameters)");
+            } else {
+                Iterator<Parameter> iter = parameters.iterator();
+                builder.append(" (with parameters: ").append(createParameterBuilder(iter.next()));
+                while (iter.hasNext()) {
+                    builder.append("; ").append(createParameterBuilder(iter.next()));
+                }
+                builder.append(")");
+            }
+            return builder.append("\n").append(trace(error));
+        }
+
+        private static StringBuilder createParameterBuilder(Parameter parameter) {
+            StringBuilder builder = new StringBuilder(parameter.tag());
+            List<Parameter.Argument> arguments = Arrays.asList(parameter.arguments());
+            if (arguments.isEmpty()) {
+                builder.append(" with no arguments");
+            } else {
+                Iterator<Parameter.Argument> iter = arguments.iterator();
+                builder.append(" with arguments: ").append(createArgumentBuilder(iter.next()));
+                while (iter.hasNext()) {
+                    builder.append(", ").append(createArgumentBuilder(iter.next()));
+                }
+            }
+            return builder;
+        }
+
+        private static StringBuilder createArgumentBuilder(Parameter.Argument argument) {
+            StringBuilder builder = new StringBuilder(argument.name()).append("=");
+            if (!Parameter.ArgumentDefault.STRING.equals(argument.stringVar())) {
+                builder.append(argument.stringVar());
+            } else if (Parameter.ArgumentDefault.INT != argument.intVar()) {
+                builder.append(argument.intVar());
+            } else if (argument.stringArray().length > 0) {
+                builder.append(Arrays.toString(argument.stringArray()));
+            } else if (argument.intArray().length > 0) {
+                builder.append(Arrays.toString(argument.intArray()));
+            }
+            return builder;
+        }
+
+        /**
+         * @return the trace without the error message
+         */
+        private static StringBuilder trace(ParameterError error) {
+            StringWriter stringWriter = new StringWriter();
+            PrintWriter writer = new PrintWriter(stringWriter);
+            error.getThrowable().printStackTrace(writer);
+            StringBuilder builder = new StringBuilder(stringWriter.getBuffer());
+            return trim(deleteFirstLine(builder));
+        }
+
+        private static StringBuilder deleteFirstLine(StringBuilder builder) {
+            return builder.delete(0, builder.indexOf("\n") + 1);
+        }
+
+        private static StringBuilder trim(StringBuilder sb) {
+            if (sb == null || sb.length() == 0) return sb;
+            for (int i = sb.length() - 1; i >= 0; i--) {
+                if (Character.isWhitespace(sb.charAt(i))) {
+                    sb.deleteCharAt(i);
+                } else {
+                    return sb;
+                }
+            }
+            return sb;
+        }
+    }
+
+    /**
+     * 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 Context} if available; null otherwise.
+     */
+    public Context getTargetContext() {
+        Context targetContext = mInstrumentation.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_MS) {
+                Thread.sleep(SLEEP_INTERVAL_MS);
+                targetContext = mInstrumentation.getTargetContext();
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted while attempting to initialize the command line.");
+        }
+        return targetContext;
+    }
+}
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
index 2feb83d..6c778b7 100644
--- 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
@@ -4,11 +4,26 @@
 
 package org.chromium.base.test.util;
 
+import android.content.Context;
+
+import junit.framework.Assert;
+
+import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.CommandLine;
+import org.chromium.base.test.BaseTestResult.PreTestHook;
+import org.chromium.base.test.util.parameter.BaseParameter;
+
 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;
+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;
 
 /**
  * Provides annotations related to command-line flag handling.
@@ -44,5 +59,93 @@
         String[] value();
     }
 
+    /**
+     * 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.
+     */
+    public static void setUp(Context targetContext, AnnotatedElement element) {
+        Assert.assertNotNull("Unable to get a non-null target context.", targetContext);
+        CommandLine.reset();
+        BaseChromiumApplication.initCommandLine(targetContext);
+        Set<String> flags = getFlags(element);
+        for (String flag : flags) {
+            CommandLine.getInstance().appendSwitch(flag);
+        }
+    }
+
+    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).
+                Assert.assertFalse("Unable to remove command-line flag \"" + flagToRemove + "\".",
+                        CommandLine.getInstance().hasSwitch(flagToRemove));
+            }
+            flags.removeAll(flagsToRemove);
+        }
+
+        return flags;
+    }
+
     private CommandLineFlags() {}
+
+    public static PreTestHook getRegistrationHook() {
+        return new PreTestHook() {
+            @Override
+            public void run(Context targetContext, Method testMethod) {
+                CommandLineFlags.setUp(targetContext, testMethod);
+            }
+
+        };
+    }
+
+    /**
+     * Instructs the test runner to execute the test with modified command-line flags.
+     * Flags to add are specified using 'stringArray' of argument named 'add',
+     * and flags to remove -- in the argument named 'remove'. A parameter without arguments
+     * instructs to run the test with default command-line flags.
+     *
+     * Example:
+     * @ParameterizedTest.Set(tests = {
+     *             @ParameterizedTest(parameters = {
+     *                         @Parameter(
+     *                                 tag = CommandLineFlags.Parameter.PARAMETER_TAG)}),
+     *             @ParameterizedTest(parameters = {
+     *                         @Parameter(
+     *                                 tag = CommandLineFlags.Parameter.PARAMETER_TAG,
+     *                                 arguments = {
+     *                                     @Parameter.Argument(
+     *                                         name = CommandLineFlags.Parameter.ADD_ARG,
+     *                                         stringArray = {'arg1', 'arg2'})
+     *             })})})
+     *
+     * Note that because the entire instrumentation test process needs to be restarted to apply
+     * modified command-line arguments, this annotation is handled by test_runner.py, not by
+     * BaseTestResult class.
+     */
+    public static class Parameter extends BaseParameter {
+        public static final String PARAMETER_TAG = "cmdlinearg-parameter";
+        public static final String ADD_ARG = "add";
+        public static final String REMOVE_ARG = "remove";
+
+        public Parameter(org.chromium.base.test.util.parameter.Parameter.Reader parameterReader) {
+            super(PARAMETER_TAG, parameterReader);
+        }
+    }
 }
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
index 11026ef..4b561a6 100644
--- 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
@@ -30,8 +30,11 @@
     /** 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";
 
+    /** Specifies the test is only valid on a device that can reach the internet. */
+    public static final String RESTRICTION_TYPE_INTERNET = "Internet";
+
     /**
      * @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
index c21bff9..b1feef5 100644
--- 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
@@ -4,6 +4,8 @@
 
 package org.chromium.base.test.util;
 
+import org.chromium.base.annotations.SuppressFBWarnings;
+
 /**
  * Utility class for scaling various timeouts by a common factor.
  * For example, to run tests under Valgrind, you might want the following:
@@ -13,6 +15,7 @@
     private static Double sTimeoutScale = null;
     private static final String PROPERTY_FILE = "/data/local/tmp/chrome_timeout_scale";
 
+    @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
     public static long scaleTimeout(long timeout) {
         if (sTimeoutScale == null) {
             try {
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
index 8765def..6d89121 100644
--- 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
@@ -21,9 +21,13 @@
 public class TestFileUtil {
     public static void createNewHtmlFile(String name, String title, String body)
             throws IOException {
-        File file = new File(name);
+        createNewHtmlFile(new File(name), title, body);
+    }
+
+    public static void createNewHtmlFile(File file, String title, String body)
+            throws IOException {
         if (!file.createNewFile()) {
-            throw new IOException("File \"" + name + "\" already exists");
+            throw new IOException("File \"" + file.getAbsolutePath() + "\" already exists");
         }
 
         Writer writer = null;
@@ -43,7 +47,10 @@
     }
 
     public static void deleteFile(String name) {
-        File file = new File(name);
+        deleteFile(new File(name));
+    }
+
+    public static void deleteFile(File file) {
         boolean deleted = file.delete();
         assert (deleted || !file.exists());
     }
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
index 93c23f7..4f62969 100644
--- 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
@@ -43,7 +43,7 @@
  */
 
 public class TestThread extends Thread {
-    private Object mThreadReadyLock;
+    private final Object mThreadReadyLock;
     private AtomicBoolean mThreadReady;
     private Handler mMainThreadHandler;
     private Handler mTestThreadHandler;
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/BaseParameter.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/BaseParameter.java
new file mode 100644
index 0000000..bc4c8e4
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/BaseParameter.java
@@ -0,0 +1,80 @@
+// Copyright 2015 The Chromium 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.parameter;
+
+/**
+ * The attributes of a single parameter.
+ */
+public class BaseParameter {
+    private final String mTag;
+    private final Parameter.Reader mParameterReader;
+
+    public BaseParameter(String tag, Parameter.Reader parameterReader) {
+        mTag = tag;
+        mParameterReader = parameterReader;
+    }
+
+    public String getTag() {
+        return mTag;
+    }
+
+    public String getStringArgument(String argumentName, String defaultString) {
+        Parameter.Argument parameterArgument = getArgument(argumentName);
+        return parameterArgument != null ? parameterArgument.stringVar() : defaultString;
+    }
+
+    public String getStringArgument(String argumentName) {
+        Parameter.Argument parameterArgument = getArgument(argumentName);
+        checkArgumentExists(parameterArgument);
+        return parameterArgument.stringVar();
+    }
+
+    public int getIntArgument(String argumentName, int defaultInt) {
+        Parameter.Argument parameterArgument = getArgument(argumentName);
+        return parameterArgument != null ? parameterArgument.intVar() : defaultInt;
+    }
+
+    public int getIntArgument(String argumentName) {
+        Parameter.Argument parameterArgument = getArgument(argumentName);
+        checkArgumentExists(parameterArgument);
+        return parameterArgument.intVar();
+    }
+
+    public String[] getStringArrayArgument(String argumentName, String[] defaultStringArray) {
+        Parameter.Argument parameterArgument = getArgument(argumentName);
+        return parameterArgument != null ? parameterArgument.stringArray() : defaultStringArray;
+    }
+
+    public String[] getStringArrayArgument(String argumentName) {
+        Parameter.Argument parameterArgument = getArgument(argumentName);
+        checkArgumentExists(parameterArgument);
+        return parameterArgument.stringArray();
+    }
+
+    public int[] getIntArrayArgument(String argumentName, int[] defaultIntArray) {
+        Parameter.Argument parameterArgument = getArgument(argumentName);
+        return parameterArgument != null ? parameterArgument.intArray() : defaultIntArray;
+    }
+
+    public int[] getIntArrayArgument(String argumentName) {
+        Parameter.Argument parameterArgument = getArgument(argumentName);
+        checkArgumentExists(parameterArgument);
+        return parameterArgument.intArray();
+    }
+
+    private Parameter.Argument getArgument(String argumentName) {
+        return mParameterReader.getParameterArgument(getTag(), argumentName);
+    }
+
+    private static void checkArgumentExists(Parameter.Argument parameterArgument) {
+        if (parameterArgument == null) {
+            throw new IllegalArgumentException("Argument must be specified");
+        }
+    }
+
+    public void setUp() throws Exception {}
+
+    public void tearDown() throws Exception {}
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameter.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameter.java
new file mode 100644
index 0000000..0d122d2
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameter.java
@@ -0,0 +1,199 @@
+// Copyright 2015 The Chromium 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.parameter;
+
+import junit.framework.TestCase;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * The annotation for an individual parameter in a {@link ParameterizedTest}.
+ *
+ * Contains all annotations required to run tests ParameterizedTests.
+ */
+public @interface Parameter {
+    String tag();
+    Argument[] arguments() default {};
+
+    /**
+     * The annotation for an individual argument in a {@link Parameter}.
+     */
+    @interface Argument {
+        String name();
+        String stringVar() default Parameter.ArgumentDefault.STRING;
+        String[] stringArray() default {};
+        int intVar() default Parameter.ArgumentDefault.INT;
+        int[] intArray() default {};
+    }
+
+    /**
+     * Default values for {@link Parameter.Argument}s.
+     *
+     * TODO (crbug.com/520232): Move to within {@link Parameter.Argument} and rename to Default
+     * when fixed.
+     */
+    final class ArgumentDefault {
+        public static final String STRING = "";
+        public static final int INT = 0;
+    }
+
+    /**
+     * The tool to read Parameter related annotations.
+     */
+    class Reader {
+        private Class mAnnotatedTestClass;
+        private AnnotatedElement mAnnotatedTestMethod;
+        private ParameterizedTest mParameterizedTest;
+
+        public Reader(TestCase testCase) {
+            try {
+                mAnnotatedTestClass = testCase.getClass();
+                mAnnotatedTestMethod = testCase.getClass().getMethod(testCase.getName());
+            } catch (NoSuchMethodException e) {
+                // ignore
+            }
+        }
+
+        /**
+         * Gets the {@link ParameterizedTest}s for the current test.
+         *
+         * @return a list of all the {@link ParameterizedTest}s for the current test.
+         */
+        public List<ParameterizedTest> getParameterizedTests() {
+            return new ArrayList<ParameterizedTest>(getParameterizedTestsImpl());
+        }
+
+        /**
+         * Gets the {@link ParameterizedTest}s for the current test as immutable list.
+         *
+         * @return a list of all the {@link ParameterizedTest}s for the current test.
+         */
+        private List<ParameterizedTest> getParameterizedTestsImpl() {
+            // Note: this must be aligned with Python code in
+            // instrumentation_test_instance.ParseCommandLineFlagParameters (regarding priority of
+            // ParameterizedTest.Set vs. ParameterizedTest) and in test_jar._GetProguardData
+            // (regarding composition of method annotations with class and superclasses
+            // annotations). Composition precedes selecting the annotation to process.
+            if (mAnnotatedTestMethod.isAnnotationPresent(ParameterizedTest.Set.class)) {
+                return Arrays.asList(getParameterizedTestSet(mAnnotatedTestMethod).tests());
+            }
+            AnnotatedElement classWithAnnotation = findClassWithAnnotation(
+                    mAnnotatedTestClass, ParameterizedTest.Set.class);
+            if (classWithAnnotation != null) {
+                return Arrays.asList(getParameterizedTestSet(classWithAnnotation).tests());
+            }
+            if (mAnnotatedTestMethod.isAnnotationPresent(ParameterizedTest.class)) {
+                return Collections.singletonList(getParameterizedTest(mAnnotatedTestMethod));
+            }
+            classWithAnnotation = findClassWithAnnotation(
+                    mAnnotatedTestClass, ParameterizedTest.class);
+            if (classWithAnnotation != null) {
+                return Collections.singletonList(getParameterizedTest(classWithAnnotation));
+            }
+            return Collections.emptyList();
+        }
+
+        /**
+         * Finds a class with the given annotation class starting from the given clazz.
+         *
+         * @return the class as {@link AnnotatedElement} or null if the class is not found.
+         */
+        private AnnotatedElement findClassWithAnnotation(
+                Class<?> clazz, Class<? extends Annotation> annotationClass) {
+            if (clazz == null || clazz.isAnnotationPresent(annotationClass)) {
+                return clazz;
+            } else {
+                return findClassWithAnnotation(clazz.getSuperclass(), annotationClass);
+            }
+        }
+
+        /**
+         * Gets the {@link ParameterizedTest} annotation of the current test.
+         *
+         * @return a {@link ParameterizedTest} of the current test's parameters.
+         */
+        private ParameterizedTest getParameterizedTest(AnnotatedElement element) {
+            return element.getAnnotation(ParameterizedTest.class);
+        }
+
+        /**
+         * Gets the {@link ParameterizedTest.Set} annotation of the current test.
+         *
+         * @return a {@link ParameterizedTest.Set} of the current test's parameters.
+         */
+        private ParameterizedTest.Set getParameterizedTestSet(AnnotatedElement element) {
+            return element.getAnnotation(ParameterizedTest.Set.class);
+        }
+
+        public boolean isParameterizedTest() {
+            return mAnnotatedTestMethod.isAnnotationPresent(ParameterizedTest.Set.class)
+                    || mAnnotatedTestMethod.isAnnotationPresent(ParameterizedTest.class)
+                    || findClassWithAnnotation(
+                            mAnnotatedTestClass, ParameterizedTest.Set.class) != null
+                    || findClassWithAnnotation(
+                            mAnnotatedTestClass, ParameterizedTest.class) != null;
+        }
+
+        public void setCurrentParameterizedTest(ParameterizedTest parameterizedTest) {
+            mParameterizedTest = parameterizedTest;
+        }
+
+        /**
+         * Gets a {@link Parameter} object for a given target parameter.
+         *
+         * @param targetParameter the name of the {@link Parameter} to get in the current
+         * parameterized test.
+         * @return the {@link Parameter} for a given {@link ParameterizedTest} with the
+         * targetParameter as its tag if it exists, otherwise returns null.
+         */
+        public Parameter getParameter(String targetParameter) {
+            if (mParameterizedTest == null || targetParameter == null) {
+                return null;
+            }
+            for (Parameter parameter : mParameterizedTest.parameters()) {
+                if (targetParameter.equals(parameter.tag())) {
+                    return parameter;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Gets the {@link Parameter.Argument} for a given {@link Parameter}.
+         *
+         * @param targetParameter the name of the {@link Parameter} to search for when looking for
+         * a {@link Parameter.Argument}.
+         * @param targetArgument the name of the {@link Parameter.Argument} to look for in the
+         * target {@link Parameter}.
+         * @return the {@link Parameter.Argument} for a given {@link ParameterizedTest} for the
+         * {@link Parameter} with the tag matching targetParameter and the argument name being
+         * targetArgument if it exists, otherwise returns null.
+         */
+        public Parameter.Argument getParameterArgument(String targetParameter,
+                String targetArgument) {
+            Parameter parameter = getParameter(targetParameter);
+            return (parameter == null) ? null : getParameterArgument(parameter, targetArgument);
+        }
+
+        public static Parameter.Argument getParameterArgument(Parameter parameter,
+                String targetArgument) {
+            if (targetArgument == null) {
+                return null;
+            }
+            for (Parameter.Argument argument : parameter.arguments()) {
+                if (targetArgument.equals(argument.name())) {
+                    return argument;
+                }
+            }
+            return null;
+        }
+    }
+}
+
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameterizable.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameterizable.java
new file mode 100644
index 0000000..f5c8ce8
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameterizable.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.test.util.parameter;
+
+import java.util.Map;
+
+/**
+ * An interface to implement on test cases to run {@link ParameterizedTest}s.
+ */
+public interface Parameterizable {
+
+    /**
+     * Gets the {@link Map} of available parameters for the test to use.
+     *
+     * @return a {@link Map} of {@link BaseParameter} objects.
+     */
+    Map<String, BaseParameter> getAvailableParameters();
+
+
+    /**
+     * Setter method for {@link Parameter.Reader}.
+     *
+     * @param parameterReader the {@link Parameter.Reader} to set.
+     */
+    void setParameterReader(Parameter.Reader parameterReader);
+
+    /**
+     * Gets a specific parameter from the current test.
+     *
+     * @param parameterTag a string with the name of the {@link BaseParameter} we want.
+     * @return a parameter that extends {@link BaseParameter} that has the matching parameterTag.
+     */
+    <T extends BaseParameter> T getAvailableParameter(String parameterTag);
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/ParameterizedTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/ParameterizedTest.java
new file mode 100644
index 0000000..65e929f
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/ParameterizedTest.java
@@ -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.
+
+package org.chromium.base.test.util.parameter;
+
+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;
+
+/**
+ * The annotation for an individual set of {@link Parameter}s to run on a single test.
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface ParameterizedTest {
+    Parameter[] parameters() default {};
+
+    /**
+     * The annotation that contains a set of {@link ParameterizedTest}s to run. A test method
+     * is attempted for every set of {@link Parameter}s in each {@link ParameterizedTest}.
+     */
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD, ElementType.TYPE})
+    @interface Set {
+        ParameterizedTest[] tests() default {};
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/parameters/MethodParameter.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/parameters/MethodParameter.java
new file mode 100644
index 0000000..c314540
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/parameters/MethodParameter.java
@@ -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.
+
+package org.chromium.base.test.util.parameter.parameters;
+
+import org.chromium.base.test.util.parameter.BaseParameter;
+import org.chromium.base.test.util.parameter.Parameter;
+
+/**
+ * Allows for passing of certain parameters arguments to function when this parameter is used.
+ */
+public class MethodParameter extends BaseParameter {
+    public static final String PARAMETER_TAG = "method-parameter";
+
+    public MethodParameter(Parameter.Reader parameterReader) {
+        super(PARAMETER_TAG, parameterReader);
+    }
+}
+
+
diff --git a/base/test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java b/base/test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java
new file mode 100644
index 0000000..b3ff57e
--- /dev/null
+++ b/base/test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java
@@ -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.
+
+package org.chromium.base.test.shadows;
+
+import android.content.Context;
+import android.support.multidex.MultiDex;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/** Do-nothing shadow for {@link android.support.multidex.MultiDex}. */
+@Implements(MultiDex.class)
+public class ShadowMultiDex {
+
+    @Implementation
+    public static void install(Context context) {
+    }
+
+}
diff --git a/base/test/expectations/OWNERS b/base/test/expectations/OWNERS
deleted file mode 100644
index 14fce2a..0000000
--- a/base/test/expectations/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-rsesek@chromium.org
diff --git a/base/test/expectations/expectation.cc b/base/test/expectations/expectation.cc
deleted file mode 100644
index 3081779..0000000
--- a/base/test/expectations/expectation.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All 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
deleted file mode 100644
index be5a9d7..0000000
--- a/base/test/expectations/expectation.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All 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
deleted file mode 100644
index c0f55a1..0000000
--- a/base/test/expectations/expectation_unittest.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All 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
deleted file mode 100644
index c7132e5..0000000
--- a/base/test/expectations/parser.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All 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
deleted file mode 100644
index 69a741a..0000000
--- a/base/test/expectations/parser.h
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All 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
deleted file mode 100644
index 074d634..0000000
--- a/base/test/expectations/parser_unittest.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All 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
index b811194..3f44d74 100644
--- a/base/test/gtest_util.cc
+++ b/base/test/gtest_util.cc
@@ -11,33 +11,43 @@
 
 namespace base {
 
+TestIdentifier::TestIdentifier() {
+}
+
 std::string FormatFullTestName(const std::string& test_case_name,
                                const std::string& test_name) {
   return test_case_name + "." + test_name;
 }
 
-std::vector<SplitTestName> GetCompiledInTests() {
+std::vector<TestIdentifier> GetCompiledInTests() {
   testing::UnitTest* const unit_test = testing::UnitTest::GetInstance();
 
-  std::vector<SplitTestName> tests;
+  std::vector<TestIdentifier> 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()));
+      TestIdentifier test_data;
+      test_data.test_case_name = test_case->name();
+      test_data.test_name = test_info->name();
+      test_data.file = test_info->file();
+      test_data.line = test_info->line();
+      tests.push_back(test_data);
     }
   }
   return tests;
 }
 
 bool WriteCompiledInTestsToFile(const FilePath& path) {
-  std::vector<SplitTestName> tests(GetCompiledInTests());
+  std::vector<TestIdentifier> 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);
+    test_info->SetString("test_case_name", tests[i].test_case_name);
+    test_info->SetString("test_name", tests[i].test_name);
+    test_info->SetString("file", tests[i].file);
+    test_info->SetInteger("line", tests[i].line);
     root.Append(test_info);
   }
 
@@ -46,12 +56,12 @@
 }
 
 bool ReadTestNamesFromFile(const FilePath& path,
-                           std::vector<SplitTestName>* output) {
+                           std::vector<TestIdentifier>* output) {
   JSONFileValueDeserializer deserializer(path);
   int error_code = 0;
   std::string error_message;
-  scoped_ptr<base::Value> value(
-      deserializer.Deserialize(&error_code, &error_message));
+  scoped_ptr<base::Value> value =
+      deserializer.Deserialize(&error_code, &error_message);
   if (!value.get())
     return false;
 
@@ -59,21 +69,27 @@
   if (!value->GetAsList(&tests))
     return false;
 
-  std::vector<base::SplitTestName> result;
+  std::vector<base::TestIdentifier> 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))
+    TestIdentifier test_data;
+
+    if (!test->GetStringASCII("test_case_name", &test_data.test_case_name))
       return false;
 
-    std::string test_name;
-    if (!test->GetStringASCII("test_name", &test_name))
+    if (!test->GetStringASCII("test_name", &test_data.test_name))
       return false;
 
-    result.push_back(std::make_pair(test_case_name, test_name));
+    if (!test->GetStringASCII("file", &test_data.file))
+      return false;
+
+    if (!test->GetInteger("line", &test_data.line))
+      return false;
+
+    result.push_back(test_data);
   }
 
   output->swap(result);
diff --git a/base/test/gtest_util.h b/base/test/gtest_util.h
index 77cc924..c0e088f 100644
--- a/base/test/gtest_util.h
+++ b/base/test/gtest_util.h
@@ -15,8 +15,14 @@
 
 class FilePath;
 
-// First value is test case name, second one is test name.
-typedef std::pair<std::string, std::string> SplitTestName;
+struct TestIdentifier {
+  TestIdentifier();
+
+  std::string test_case_name;
+  std::string test_name;
+  std::string file;
+  int line;
+};
 
 // 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".
@@ -25,7 +31,7 @@
 
 // Returns a vector of gtest-based tests compiled into
 // current executable.
-std::vector<SplitTestName> GetCompiledInTests();
+std::vector<TestIdentifier> GetCompiledInTests();
 
 // Writes the list of gtest-based tests compiled into
 // current executable as a JSON file. Returns true on success.
@@ -35,7 +41,7 @@
 // Returns true on success.
 bool ReadTestNamesFromFile(
     const FilePath& path,
-    std::vector<SplitTestName>* output) WARN_UNUSED_RESULT;
+    std::vector<TestIdentifier>* output) WARN_UNUSED_RESULT;
 
 }  // namespace base
 
diff --git a/base/test/gtest_xml_unittest_result_printer.cc b/base/test/gtest_xml_unittest_result_printer.cc
new file mode 100644
index 0000000..192c228
--- /dev/null
+++ b/base/test/gtest_xml_unittest_result_printer.cc
@@ -0,0 +1,77 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gtest_xml_unittest_result_printer.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+
+namespace base {
+
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter() : output_file_(NULL) {
+}
+
+XmlUnitTestResultPrinter::~XmlUnitTestResultPrinter() {
+  if (output_file_) {
+    fprintf(output_file_, "</testsuites>\n");
+    fflush(output_file_);
+    CloseFile(output_file_);
+  }
+}
+
+bool XmlUnitTestResultPrinter::Initialize(const FilePath& output_file_path) {
+  DCHECK(!output_file_);
+  output_file_ = OpenFile(output_file_path, "w");
+  if (!output_file_)
+    return false;
+
+  fprintf(output_file_,
+          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites>\n");
+  fflush(output_file_);
+
+  return true;
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseStart(
+    const testing::TestCase& test_case) {
+  fprintf(output_file_, "  <testsuite>\n");
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestStart(
+    const testing::TestInfo& test_info) {
+  // This is our custom extension - it helps to recognize which test was
+  // running when the test binary crashed. Note that we cannot even open the
+  // <testcase> tag here - it requires e.g. run time of the test to be known.
+  fprintf(output_file_,
+          "    <x-teststart name=\"%s\" classname=\"%s\" />\n",
+          test_info.name(),
+          test_info.test_case_name());
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestEnd(const testing::TestInfo& test_info) {
+  fprintf(output_file_,
+          "    <testcase name=\"%s\" status=\"run\" time=\"%.3f\""
+          " classname=\"%s\">\n",
+          test_info.name(),
+          static_cast<double>(test_info.result()->elapsed_time()) /
+              Time::kMillisecondsPerSecond,
+          test_info.test_case_name());
+  if (test_info.result()->Failed()) {
+    fprintf(output_file_,
+            "      <failure message=\"\" type=\"\"></failure>\n");
+  }
+  fprintf(output_file_, "    </testcase>\n");
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseEnd(
+    const testing::TestCase& test_case) {
+  fprintf(output_file_, "  </testsuite>\n");
+  fflush(output_file_);
+}
+
+}  // namespace base
diff --git a/base/test/gtest_xml_unittest_result_printer.h b/base/test/gtest_xml_unittest_result_printer.h
new file mode 100644
index 0000000..3b06b85
--- /dev/null
+++ b/base/test/gtest_xml_unittest_result_printer.h
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
+#define BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
+
+#include <stdio.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FilePath;
+
+// Generates an XML output file. Format is very close to GTest, but has
+// extensions needed by the test launcher.
+class XmlUnitTestResultPrinter : public testing::EmptyTestEventListener {
+ public:
+  XmlUnitTestResultPrinter();
+  ~XmlUnitTestResultPrinter() override;
+
+  // Must be called before adding as a listener. Returns true on success.
+  bool Initialize(const FilePath& output_file_path) WARN_UNUSED_RESULT;
+
+ private:
+  // testing::EmptyTestEventListener:
+  void OnTestCaseStart(const testing::TestCase& test_case) override;
+  void OnTestStart(const testing::TestInfo& test_info) override;
+  void OnTestEnd(const testing::TestInfo& test_info) override;
+  void OnTestCaseEnd(const testing::TestCase& test_case) override;
+
+  FILE* output_file_;
+
+  DISALLOW_COPY_AND_ASSIGN(XmlUnitTestResultPrinter);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
diff --git a/base/test/gtest_xml_util.cc b/base/test/gtest_xml_util.cc
index db8cc2d..e24d522 100644
--- a/base/test/gtest_xml_util.cc
+++ b/base/test/gtest_xml_util.cc
@@ -21,73 +21,12 @@
   va_list args;
   va_start(args, message);
   std::string* error = static_cast<std::string*>(context);
-  base::StringAppendV(error, message, args);
+  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) {
diff --git a/base/test/gtest_xml_util.h b/base/test/gtest_xml_util.h
index 9ff2406..b023f80 100644
--- a/base/test/gtest_xml_util.h
+++ b/base/test/gtest_xml_util.h
@@ -7,37 +7,13 @@
 
 #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
diff --git a/base/test/histogram_tester.cc b/base/test/histogram_tester.cc
index ea738b0..7fcde6d 100644
--- a/base/test/histogram_tester.cc
+++ b/base/test/histogram_tester.cc
@@ -6,6 +6,7 @@
 
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_samples.h"
+#include "base/metrics/sample_map.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -73,17 +74,60 @@
   }
 }
 
+std::vector<Bucket> HistogramTester::GetAllSamples(
+    const std::string& name) const {
+  std::vector<Bucket> samples;
+  scoped_ptr<HistogramSamples> snapshot =
+      GetHistogramSamplesSinceCreation(name);
+  if (snapshot) {
+    for (auto it = snapshot->Iterator(); !it->Done(); it->Next()) {
+      HistogramBase::Sample sample;
+      HistogramBase::Count count;
+      it->Get(&sample, nullptr, &count);
+      samples.push_back(Bucket(sample, count));
+    }
+  }
+  return samples;
+}
+
+HistogramTester::CountsMap HistogramTester::GetTotalCountsForPrefix(
+    const std::string& query) const {
+  EXPECT_TRUE(query.find('.') != std::string::npos)
+      << "|query| ought to contain at least one period, to avoid matching too"
+      << " many histograms.";
+
+  // Find matches by using the prefix-matching logic built into GetSnapshot().
+  StatisticsRecorder::Histograms query_matches;
+  StatisticsRecorder::GetSnapshot(query, &query_matches);
+
+  CountsMap result;
+  for (base::HistogramBase* histogram : query_matches) {
+    scoped_ptr<HistogramSamples> new_samples =
+        GetHistogramSamplesSinceCreation(histogram->histogram_name());
+    // Omit unchanged histograms from the result.
+    if (new_samples->TotalCount()) {
+      result[histogram->histogram_name()] = new_samples->TotalCount();
+    }
+  }
+  return result;
+}
+
 scoped_ptr<HistogramSamples> HistogramTester::GetHistogramSamplesSinceCreation(
-    const std::string& histogram_name) {
+    const std::string& histogram_name) const {
   HistogramBase* histogram = StatisticsRecorder::FindHistogram(histogram_name);
+  // Whether the histogram exists or not may not depend on the current test
+  // calling this method, but rather on which tests ran before and possibly
+  // generated a histogram or not (see http://crbug.com/473689). To provide a
+  // response which is independent of the previously run tests, this method
+  // creates empty samples in the absence of the histogram, rather than
+  // returning null.
   if (!histogram)
-    return scoped_ptr<HistogramSamples>();
+    return scoped_ptr<HistogramSamples>(new SampleMap);
   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();
+  auto original_samples_it = histograms_snapshot_.find(histogram_name);
+  if (original_samples_it != histograms_snapshot_.end())
+    named_samples->Subtract(*original_samples_it->second);
+  return named_samples;
 }
 
 void HistogramTester::CheckBucketCount(
@@ -120,4 +164,12 @@
       << expected_count << "). It has (" << actual_count << ").";
 }
 
+bool Bucket::operator==(const Bucket& other) const {
+  return min == other.min && count == other.count;
+}
+
+void PrintTo(const Bucket& bucket, std::ostream* os) {
+  *os << "Bucket " << bucket.min << ": " << bucket.count;
+}
+
 }  // namespace base
diff --git a/base/test/histogram_tester.h b/base/test/histogram_tester.h
index 96317f9..cfab3c6 100644
--- a/base/test/histogram_tester.h
+++ b/base/test/histogram_tester.h
@@ -6,7 +6,10 @@
 #define BASE_TEST_HISTOGRAM_TESTER_H_
 
 #include <map>
+#include <ostream>
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
@@ -15,6 +18,7 @@
 
 namespace base {
 
+struct Bucket;
 class HistogramSamples;
 
 // HistogramTester provides a simple interface for examining histograms, UMA
@@ -22,6 +26,8 @@
 // getting logged as intended.
 class HistogramTester {
  public:
+  using CountsMap = std::map<std::string, base::HistogramBase::Count>;
+
   // The constructor will call StatisticsRecorder::Initialize() for you. Also,
   // this takes a snapshot of all current histograms counts.
   HistogramTester();
@@ -47,10 +53,48 @@
   void ExpectTotalCount(const std::string& name,
                         base::HistogramBase::Count count) const;
 
+  // Returns a list of all of the buckets recorded since creation of this
+  // object, as vector<Bucket>, where the Bucket represents the min boundary of
+  // the bucket and the count of samples recorded to that bucket since creation.
+  //
+  // Example usage, using gMock:
+  //   EXPECT_THAT(histogram_tester.GetAllSamples("HistogramName"),
+  //               ElementsAre(Bucket(1, 5), Bucket(2, 10), Bucket(3, 5)));
+  //
+  // If you build the expected list programmatically, you can use ContainerEq:
+  //   EXPECT_THAT(histogram_tester.GetAllSamples("HistogramName"),
+  //               ContainerEq(expected_buckets));
+  //
+  // or EXPECT_EQ if you prefer not to depend on gMock, at the expense of a
+  // slightly less helpful failure message:
+  //   EXPECT_EQ(expected_buckets,
+  //             histogram_tester.GetAllSamples("HistogramName"));
+  std::vector<Bucket> GetAllSamples(const std::string& name) const;
+
+  // Finds histograms whose names start with |query|, and returns them along
+  // with the counts of any samples added since the creation of this object.
+  // Histograms that are unchanged are omitted from the result. The return value
+  // is a map whose keys are the histogram name, and whose values are the sample
+  // count.
+  //
+  // This is useful for cases where the code under test is choosing among a
+  // family of related histograms and incrementing one of them. Typically you
+  // should pass the result of this function directly to EXPECT_THAT.
+  //
+  // Example usage, using gmock (which produces better failure messages):
+  //   #include "testing/gmock/include/gmock/gmock.h"
+  // ...
+  //   base::HistogramTester::CountsMap expected_counts;
+  //   expected_counts["MyMetric.A"] = 1;
+  //   expected_counts["MyMetric.B"] = 1;
+  //   EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix("MyMetric."),
+  //               testing::ContainerEq(expected_counts));
+  CountsMap GetTotalCountsForPrefix(const std::string& query) 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);
+      const std::string& histogram_name) const;
 
  private:
   // Verifies and asserts that value in the |sample| bucket matches the
@@ -76,6 +120,18 @@
   DISALLOW_COPY_AND_ASSIGN(HistogramTester);
 };
 
+struct Bucket {
+  Bucket(base::HistogramBase::Sample min, base::HistogramBase::Count count)
+      : min(min), count(count) {}
+
+  bool operator==(const Bucket& other) const;
+
+  base::HistogramBase::Sample min;
+  base::HistogramBase::Count count;
+};
+
+void PrintTo(const Bucket& value, std::ostream* os);
+
 }  // namespace base
 
 #endif  // BASE_TEST_HISTOGRAM_TESTER_H_
diff --git a/base/test/histogram_tester_unittest.cc b/base/test/histogram_tester_unittest.cc
index a03ee13..21b8170 100644
--- a/base/test/histogram_tester_unittest.cc
+++ b/base/test/histogram_tester_unittest.cc
@@ -5,16 +5,25 @@
 #include "base/test/histogram_tester.h"
 
 #include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/histogram_samples.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace base {
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
 
-const std::string kHistogram1 = "Test1";
-const std::string kHistogram2 = "Test2";
-const std::string kHistogram3 = "Test3";
-const std::string kHistogram4 = "Test4";
+namespace {
+
+const char kHistogram1[] = "Test1";
+const char kHistogram2[] = "Test2";
+const char kHistogram3[] = "Test3";
+const char kHistogram4[] = "Test4";
+const char kHistogram5[] = "Test5";
+
+}  // namespace
+
+namespace base {
 
 typedef testing::Test HistogramTesterTest;
 
@@ -25,19 +34,32 @@
   HistogramTester tester;
 
   // Verify that no histogram is recorded.
-  scoped_ptr<HistogramSamples> samples(
-      tester.GetHistogramSamplesSinceCreation(kHistogram1));
-  EXPECT_FALSE(samples);
+  tester.ExpectTotalCount(kHistogram1, 0);
 
   // Record a histogram after the creation of the recorder.
   UMA_HISTOGRAM_BOOLEAN(kHistogram1, true);
 
   // Verify that one histogram is recorded.
-  samples = tester.GetHistogramSamplesSinceCreation(kHistogram1);
+  scoped_ptr<HistogramSamples> samples(
+      tester.GetHistogramSamplesSinceCreation(kHistogram1));
   EXPECT_TRUE(samples);
   EXPECT_EQ(1, samples->TotalCount());
 }
 
+TEST_F(HistogramTesterTest, GetHistogramSamplesSinceCreationNotNull) {
+  // Chose the histogram name uniquely, to ensure nothing was recorded for it so
+  // far.
+  static const char kHistogram[] =
+      "GetHistogramSamplesSinceCreationNotNullHistogram";
+  HistogramTester tester;
+
+  // Verify that the returned samples are empty but not null.
+  scoped_ptr<HistogramSamples> samples(
+      tester.GetHistogramSamplesSinceCreation(kHistogram1));
+  EXPECT_TRUE(samples);
+  tester.ExpectTotalCount(kHistogram, 0);
+}
+
 TEST_F(HistogramTesterTest, TestUniqueSample) {
   HistogramTester tester;
 
@@ -78,4 +100,20 @@
   tester.ExpectTotalCount(kHistogram4, 1);
 }
 
+TEST_F(HistogramTesterTest, TestGetAllSamples) {
+  HistogramTester tester;
+  UMA_HISTOGRAM_ENUMERATION(kHistogram5, 2, 5);
+  UMA_HISTOGRAM_ENUMERATION(kHistogram5, 3, 5);
+  UMA_HISTOGRAM_ENUMERATION(kHistogram5, 3, 5);
+  UMA_HISTOGRAM_ENUMERATION(kHistogram5, 5, 5);
+
+  EXPECT_THAT(tester.GetAllSamples(kHistogram5),
+              ElementsAre(Bucket(2, 1), Bucket(3, 2), Bucket(5, 1)));
+}
+
+TEST_F(HistogramTesterTest, TestGetAllSamples_NoSamples) {
+  HistogramTester tester;
+  EXPECT_THAT(tester.GetAllSamples(kHistogram5), IsEmpty());
+}
+
 }  // namespace base
diff --git a/base/test/icu_test_util.cc b/base/test/icu_test_util.cc
new file mode 100644
index 0000000..a1a8029
--- /dev/null
+++ b/base/test/icu_test_util.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/test/icu_test_util.h"
+
+#include "base/i18n/rtl.h"
+#include "third_party/icu/source/common/unicode/uloc.h"
+
+namespace base {
+namespace test {
+
+ScopedRestoreICUDefaultLocale::ScopedRestoreICUDefaultLocale()
+    : default_locale_(uloc_getDefault()) {}
+
+ScopedRestoreICUDefaultLocale::~ScopedRestoreICUDefaultLocale() {
+  i18n::SetICUDefaultLocale(default_locale_.data());
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/test/icu_test_util.h b/base/test/icu_test_util.h
new file mode 100644
index 0000000..6a75eed
--- /dev/null
+++ b/base/test/icu_test_util.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 BASE_ICU_TEST_UTIL_H_
+#define BASE_ICU_TEST_UTIL_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+namespace base {
+namespace test {
+
+class ScopedRestoreICUDefaultLocale {
+ public:
+  ScopedRestoreICUDefaultLocale();
+  ~ScopedRestoreICUDefaultLocale();
+
+ private:
+  std::string default_locale_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedRestoreICUDefaultLocale);
+};
+
+}  // namespace test
+}  // namespace base
+
+#endif  // BASE_ICU_TEST_UTIL_H_
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index 7f258f5..b1a1a89 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -25,6 +25,7 @@
 #include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/pattern.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -433,7 +434,9 @@
 
 }  // namespace
 
+const char kGTestBreakOnFailure[] = "gtest_break_on_failure";
 const char kGTestFilterFlag[] = "gtest_filter";
+const char kGTestFlagfileFlag[] = "gtest_flagfile";
 const char kGTestHelpFlag[]   = "gtest_help";
 const char kGTestListTestsFlag[] = "gtest_list_tests";
 const char kGTestRepeatFlag[] = "gtest_repeat";
@@ -449,12 +452,14 @@
       total_shards_(1),
       shard_index_(0),
       cycles_(1),
+      test_found_count_(0),
       test_started_count_(0),
       test_finished_count_(0),
       test_success_count_(0),
       test_broken_count_(0),
       retry_count_(0),
       retry_limit_(0),
+      force_run_broken_tests_(false),
       run_result_(true),
       watchdog_timer_(FROM_HERE,
                       TimeDelta::FromSeconds(kOutputTimeoutSeconds),
@@ -560,8 +565,9 @@
                  << ": " << print_test_stdio;
   }
   if (print_snippet) {
-    std::vector<std::string> snippet_lines;
-    SplitStringDontTrim(result.output_snippet, '\n', &snippet_lines);
+    std::vector<std::string> snippet_lines = SplitString(
+        result.output_snippet, "\n", base::KEEP_WHITESPACE,
+        base::SPLIT_WANT_ALL);
     if (snippet_lines.size() > kOutputSnippetLinesLimit) {
       size_t truncated_size = snippet_lines.size() - kOutputSnippetLinesLimit;
       snippet_lines.erase(
@@ -569,7 +575,7 @@
           snippet_lines.begin() + truncated_size);
       snippet_lines.insert(snippet_lines.begin(), "<truncated>");
     }
-    fprintf(stdout, "%s", JoinString(snippet_lines, "\n").c_str());
+    fprintf(stdout, "%s", base::JoinString(snippet_lines, "\n").c_str());
     fflush(stdout);
   }
 
@@ -616,8 +622,8 @@
     test_broken_count_++;
   }
   size_t broken_threshold =
-      std::max(static_cast<size_t>(20), test_started_count_ / 10);
-  if (test_broken_count_ >= broken_threshold) {
+      std::max(static_cast<size_t>(20), test_found_count_ / 10);
+  if (!force_run_broken_tests_ && test_broken_count_ >= broken_threshold) {
     fprintf(stdout, "Too many badly broken tests (%" PRIuS "), exiting now.\n",
             test_broken_count_);
     fflush(stdout);
@@ -641,7 +647,7 @@
     return;
   }
 
-  if (tests_to_retry_.size() >= broken_threshold) {
+  if (!force_run_broken_tests_ && tests_to_retry_.size() >= broken_threshold) {
     fprintf(stdout,
             "Too many failing tests (%" PRIuS "), skipping retries.\n",
             tests_to_retry_.size());
@@ -753,6 +759,9 @@
     retry_limit_ = 3;
   }
 
+  if (command_line->HasSwitch(switches::kTestLauncherForceRunBrokenTests))
+    force_run_broken_tests_ = true;
+
   if (command_line->HasSwitch(switches::kTestLauncherJobs)) {
     int jobs = -1;
     if (!StringToInt(command_line->GetSwitchValueASCII(
@@ -790,8 +799,8 @@
       return false;
     }
 
-    std::vector<std::string> filter_lines;
-    SplitString(filter, '\n', &filter_lines);
+    std::vector<std::string> filter_lines = SplitString(
+        filter, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
     for (size_t i = 0; i < filter_lines.size(); i++) {
       if (filter_lines[i].empty())
         continue;
@@ -807,13 +816,18 @@
     std::string filter = command_line->GetSwitchValueASCII(kGTestFilterFlag);
     size_t dash_pos = filter.find('-');
     if (dash_pos == std::string::npos) {
-      SplitString(filter, ':', &positive_test_filter_);
+      positive_test_filter_ = SplitString(
+          filter, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
     } else {
       // Everything up to the dash.
-      SplitString(filter.substr(0, dash_pos), ':', &positive_test_filter_);
+      positive_test_filter_ = SplitString(
+          filter.substr(0, dash_pos), ":", base::TRIM_WHITESPACE,
+          base::SPLIT_WANT_ALL);
 
       // Everything after the dash.
-      SplitString(filter.substr(dash_pos + 1), ':', &negative_test_filter_);
+      negative_test_filter_ = SplitString(
+          filter.substr(dash_pos + 1), ":", base::TRIM_WHITESPACE,
+          base::SPLIT_WANT_ALL);
     }
   }
 
@@ -896,9 +910,9 @@
   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);
+        tests_[i].test_case_name, tests_[i].test_name);
 
-    results_tracker_.AddTest(test_name);
+    results_tracker_.AddTest(test_name, tests_[i].file, tests_[i].line);
 
     const CommandLine* command_line = CommandLine::ForCurrentProcess();
     if (test_name.find("DISABLED") != std::string::npos) {
@@ -909,8 +923,13 @@
         continue;
     }
 
-    if (!launcher_delegate_->ShouldRunTest(tests_[i].first, tests_[i].second))
+    if (!launcher_delegate_->ShouldRunTest(
+        tests_[i].test_case_name, tests_[i].test_name)) {
       continue;
+    }
+
+    // Count tests in the binary, before we apply filter and sharding.
+    test_found_count_++;
 
     // Skip the test that doesn't match the filter (if given).
     if (!positive_test_filter_.empty()) {
@@ -954,14 +973,18 @@
 }
 
 void TestLauncher::RunTestIteration() {
-  if (cycles_ == 0) {
-    MessageLoop::current()->Quit();
+  const bool stop_on_failure =
+      CommandLine::ForCurrentProcess()->HasSwitch(kGTestBreakOnFailure);
+  if (cycles_ == 0 ||
+      (stop_on_failure && test_success_count_ != test_finished_count_)) {
+    MessageLoop::current()->QuitWhenIdle();
     return;
   }
 
   // Special value "-1" means "repeat indefinitely".
   cycles_ = (cycles_ == -1) ? cycles_ : cycles_ - 1;
 
+  test_found_count_ = 0;
   test_started_count_ = 0;
   test_finished_count_ = 0;
   test_success_count_ = 0;
diff --git a/base/test/launcher/test_launcher.h b/base/test/launcher/test_launcher.h
index 544df63..571a318 100644
--- a/base/test/launcher/test_launcher.h
+++ b/base/test/launcher/test_launcher.h
@@ -31,6 +31,7 @@
 
 // Constants for GTest command-line flags.
 extern const char kGTestFilterFlag[];
+extern const char kGTestFlagfileFlag[];
 extern const char kGTestHelpFlag[];
 extern const char kGTestListTestsFlag[];
 extern const char kGTestRepeatFlag[];
@@ -43,7 +44,7 @@
  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;
+  virtual bool GetTests(std::vector<TestIdentifier>* 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
@@ -160,7 +161,10 @@
   std::vector<std::string> negative_test_filter_;
 
   // Tests to use (cached result of TestLauncherDelegate::GetTests).
-  std::vector<SplitTestName> tests_;
+  std::vector<TestIdentifier> tests_;
+
+  // Number of tests found in this binary.
+  size_t test_found_count_;
 
   // Number of tests started in this iteration.
   size_t test_started_count_;
@@ -181,6 +185,10 @@
   // Maximum number of retries per iteration.
   size_t retry_limit_;
 
+  // If true will not early exit nor skip retries even if too many tests are
+  // broken.
+  bool force_run_broken_tests_;
+
   // Tests to retry in this iteration.
   std::set<std::string> tests_to_retry_;
 
@@ -190,7 +198,7 @@
   TestResultsTracker results_tracker_;
 
   // Watchdog timer to make sure we do not go without output for too long.
-  DelayTimer<TestLauncher> watchdog_timer_;
+  DelayTimer watchdog_timer_;
 
   // Number of jobs to run in parallel.
   size_t parallel_jobs_;
diff --git a/base/test/launcher/test_launcher_ios.cc b/base/test/launcher/test_launcher_ios.cc
index ecd31ae..a7243f7 100644
--- a/base/test/launcher/test_launcher_ios.cc
+++ b/base/test/launcher/test_launcher_ios.cc
@@ -88,7 +88,7 @@
     return true;
   }
 
-  bool GetTests(std::vector<base::SplitTestName>* output) override {
+  bool GetTests(std::vector<base::TestIdentifier>* output) override {
     base::ScopedTempDir temp_dir;
     if (!temp_dir.CreateUniqueTempDirUnderPath(writable_path_))
       return false;
@@ -121,7 +121,7 @@
     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, ":"));
+                               base::JoinString(test_names, ":"));
     return cmd_line;
   }
 
diff --git a/base/test/launcher/test_launcher_nacl_nonsfi.cc b/base/test/launcher/test_launcher_nacl_nonsfi.cc
new file mode 100644
index 0000000..cf6bd94
--- /dev/null
+++ b/base/test/launcher/test_launcher_nacl_nonsfi.cc
@@ -0,0 +1,160 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "base/test/launcher/test_launcher.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+
+namespace base {
+
+namespace {
+
+const char kHelpFlag[] = "help";
+
+void PrintUsage() {
+  fprintf(stdout,
+          "Runs tests using the gtest framework, each batch of tests being\n"
+          "run in their own process. Supported command-line flags:\n"
+          "\n"
+          " Common flags:\n"
+          "  --gtest_filter=...\n"
+          "    Runs a subset of tests (see --gtest_help for more info).\n"
+          "\n"
+          "  --help\n"
+          "    Shows this message.\n"
+          "\n"
+          " Other flags:\n"
+          "  --test-launcher-retry-limit=N\n"
+          "    Sets the limit of test retries on failures to N.\n"
+          "\n"
+          "  --test-launcher-summary-output=PATH\n"
+          "    Saves a JSON machine-readable summary of the run.\n"
+          "\n"
+          "  --test-launcher-print-test-stdio=auto|always|never\n"
+          "    Controls when full test output is printed.\n"
+          "    auto means to print it when the test failed.\n"
+          "\n"
+          "  --test-launcher-total-shards=N\n"
+          "    Sets the total number of shards to N.\n"
+          "\n"
+          "  --test-launcher-shard-index=N\n"
+          "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n");
+  fflush(stdout);
+}
+
+class NonSfiUnitTestPlatformDelegate : public base::UnitTestPlatformDelegate {
+ public:
+  NonSfiUnitTestPlatformDelegate() {
+  }
+
+  bool Init(const std::string& test_binary) {
+    base::FilePath dir_exe;
+    if (!PathService::Get(base::DIR_EXE, &dir_exe)) {
+      LOG(ERROR) << "Failed to get directory of the current executable.";
+      return false;
+    }
+
+    test_path_ = dir_exe.AppendASCII(test_binary);
+    return true;
+  }
+
+ private:
+  bool CreateTemporaryFile(base::FilePath* path) override {
+    if (!base::CreateNewTempDirectory(base::FilePath::StringType(), path))
+      return false;
+    *path = path->AppendASCII("test_results.xml");
+    return true;
+  }
+
+  bool GetTests(std::vector<base::TestIdentifier>* output) override {
+    base::FilePath output_file;
+    if (!base::CreateTemporaryFile(&output_file)) {
+      LOG(ERROR) << "Failed to create a temp file.";
+      return false;
+    }
+
+    base::CommandLine cmd_line(test_path_);
+    cmd_line.AppendSwitchPath(switches::kTestLauncherListTests, output_file);
+
+    base::LaunchOptions launch_options;
+    launch_options.wait = true;
+
+    if (!base::LaunchProcess(cmd_line, launch_options).IsValid())
+      return false;
+
+    return base::ReadTestNamesFromFile(output_file, output);
+  }
+
+  std::string GetWrapperForChildGTestProcess() override {
+    return std::string();
+  }
+
+  base::CommandLine GetCommandLineForChildGTestProcess(
+      const std::vector<std::string>& test_names,
+      const base::FilePath& output_file) override {
+    base::CommandLine cmd_line(test_path_);
+    cmd_line.AppendSwitchPath(
+        switches::kTestLauncherOutput, output_file);
+    cmd_line.AppendSwitchASCII(
+        base::kGTestFilterFlag, base::JoinString(test_names, ":"));
+    return cmd_line;
+  }
+
+  void RelaunchTests(base::TestLauncher* test_launcher,
+                     const std::vector<std::string>& test_names,
+                     int launch_flags) override {
+    RunUnitTestsBatch(test_launcher, this, test_names, launch_flags);
+  }
+
+  base::FilePath test_path_;
+};
+
+}  // namespace
+
+int TestLauncherNonSfiMain(const std::string& test_binary) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) {
+    PrintUsage();
+    return 0;
+  }
+
+  base::TimeTicks start_time(base::TimeTicks::Now());
+
+  TestTimeouts::Initialize();
+
+  base::MessageLoopForIO message_loop;
+
+  NonSfiUnitTestPlatformDelegate platform_delegate;
+  if (!platform_delegate.Init(test_binary)) {
+    fprintf(stderr, "Failed to initialize test launcher.\n");
+    fflush(stderr);
+    return 1;
+  }
+
+  base::UnitTestLauncherDelegate delegate(&platform_delegate, 10, true);
+  base::TestLauncher launcher(&delegate, base::SysInfo::NumberOfProcessors());
+  bool success = launcher.Run();
+
+  fprintf(stdout, "Tests took %" PRId64 " seconds.\n",
+          (base::TimeTicks::Now() - start_time).InSeconds());
+  fflush(stdout);
+  return success ? 0 : 1;
+}
+
+}  // namespace base
diff --git a/base/test/launcher/test_launcher_nacl_nonsfi.h b/base/test/launcher/test_launcher_nacl_nonsfi.h
new file mode 100644
index 0000000..6cb3785
--- /dev/null
+++ b/base/test/launcher/test_launcher_nacl_nonsfi.h
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_TEST_LAUNCHER_NACL_NONSFI_H_
+#define BASE_TEST_LAUNCHER_TEST_LAUNCHER_NACL_NONSFI_H_
+
+#include <string>
+
+namespace base {
+
+// Launches the NaCl Non-SFI test binary |test_binary|.
+int TestLauncherNonSfiMain(const std::string& test_binary);
+
+}  // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_TEST_LAUNCHER_NACL_NONSFI_H_
diff --git a/base/test/launcher/test_results_tracker.cc b/base/test/launcher/test_results_tracker.cc
index c4cb233..8516a48 100644
--- a/base/test/launcher/test_results_tracker.cc
+++ b/base/test/launcher/test_results_tracker.cc
@@ -4,6 +4,8 @@
 
 #include "base/test/launcher/test_results_tracker.h"
 
+#include <utility>
+
 #include "base/base64.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -25,26 +27,6 @@
 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_", "");
@@ -159,10 +141,13 @@
   per_iteration_data_.push_back(PerIterationData());
 }
 
-void TestResultsTracker::AddTest(const std::string& test_name) {
+void TestResultsTracker::AddTest(
+    const std::string& test_name, const std::string& file, int line) {
   // 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));
+
+  test_locations_.insert(std::make_pair(test_name, CodeLocation(file, line)));
 }
 
 void TestResultsTracker::AddDisabledTest(const std::string& test_name) {
@@ -243,19 +228,19 @@
   for (const auto& global_tag : global_tags_) {
     global_tags->AppendString(global_tag);
   }
-  summary_root->Set("global_tags", global_tags.Pass());
+  summary_root->Set("global_tags", std::move(global_tags));
 
   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());
+  summary_root->Set("all_tests", std::move(all_tests));
 
   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());
+  summary_root->Set("disabled_tests", std::move(disabled_tests));
 
   scoped_ptr<ListValue> per_iteration_data(new ListValue);
 
@@ -278,16 +263,20 @@
             "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);
+        bool lossless_snippet = false;
+        if (IsStringUTF8(test_result.output_snippet)) {
+          test_result_value->SetString(
+              "output_snippet", test_result.output_snippet);
+          lossless_snippet = true;
+        } else {
+          test_result_value->SetString(
+              "output_snippet",
+              "<non-UTF-8 snippet, see output_snippet_base64>");
+        }
+
+        // TODO(phajdan.jr): Fix typo in JSON key (losless -> lossless)
+        // making sure not to break any consumers of this data.
+        test_result_value->SetBoolean("losless_snippet", lossless_snippet);
 
         // Also include the raw version (base64-encoded so that it can be safely
         // JSON-serialized - there are no guarantees about character encoding
@@ -297,14 +286,14 @@
         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());
+        test_results->Append(std::move(test_result_value));
       }
 
       current_iteration_data->SetWithoutPathExpansion(j->first,
-                                                      test_results.Pass());
+                                                      std::move(test_results));
     }
-    per_iteration_data->Append(current_iteration_data.Pass());
-    summary_root->Set("per_iteration_data", per_iteration_data.Pass());
+    per_iteration_data->Append(std::move(current_iteration_data));
+    summary_root->Set("per_iteration_data", std::move(per_iteration_data));
   }
 
   JSONFileValueSerializer serializer(path);
@@ -338,6 +327,32 @@
   }
 }
 
+// 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 TestResultsTracker::PrintTests(InputIterator first,
+                                    InputIterator last,
+                                    const std::string& description) const {
+  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 (%s:%d)\n",
+            (*i).c_str(),
+            test_locations_.at(*i).file.c_str(),
+            test_locations_.at(*i).line);
+  }
+  fflush(stdout);
+}
+
+
 TestResultsTracker::AggregateTestResult::AggregateTestResult() {
 }
 
diff --git a/base/test/launcher/test_results_tracker.h b/base/test/launcher/test_results_tracker.h
index 2bddebc..53a4e56 100644
--- a/base/test/launcher/test_results_tracker.h
+++ b/base/test/launcher/test_results_tracker.h
@@ -42,7 +42,7 @@
 
   // 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);
+  void AddTest(const std::string& test_name, const std::string& file, int line);
 
   // Adds |test_name| to the set of disabled tests.
   void AddDisabledTest(const std::string& test_name);
@@ -77,6 +77,11 @@
  private:
   void GetTestStatusForIteration(int iteration, TestStatusMap* map) const;
 
+  template<typename InputIterator>
+  void PrintTests(InputIterator first,
+                  InputIterator last,
+                  const std::string& description) const;
+
   struct AggregateTestResult {
     AggregateTestResult();
     ~AggregateTestResult();
@@ -93,6 +98,14 @@
     ResultsMap results;
   };
 
+  struct CodeLocation {
+    CodeLocation(const std::string& f, int l) : file(f), line(l) {
+    }
+
+    std::string file;
+    int line;
+  };
+
   ThreadChecker thread_checker_;
 
   // Set of global tags, i.e. strings indicating conditions that apply to
@@ -102,6 +115,8 @@
   // Set of all test names discovered in the current executable.
   std::set<std::string> all_tests_;
 
+  std::map<std::string, CodeLocation> test_locations_;
+
   // Set of all disabled tests in the current executable.
   std::set<std::string> disabled_tests_;
 
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index ab6fa72..9cd7d71 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -4,6 +4,7 @@
 
 #include "base/test/launcher/unit_test_launcher.h"
 
+#include "base/base_switches.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
@@ -95,7 +96,7 @@
 
  private:
   // UnitTestPlatformDelegate:
-  bool GetTests(std::vector<SplitTestName>* output) override {
+  bool GetTests(std::vector<TestIdentifier>* output) override {
     *output = GetCompiledInTests();
     return true;
   }
@@ -112,9 +113,19 @@
       const base::FilePath& output_file) override {
     CommandLine new_cmd_line(*CommandLine::ForCurrentProcess());
 
+    CHECK(temp_dir_.IsValid() || temp_dir_.CreateUniqueTempDir());
+    FilePath temp_file;
+    CHECK(CreateTemporaryFileInDir(temp_dir_.path(), &temp_file));
+    std::string long_flags(
+        std::string("--") + kGTestFilterFlag + "=" +
+        JoinString(test_names, ":"));
+    CHECK_EQ(static_cast<int>(long_flags.size()),
+             WriteFile(temp_file,
+                       long_flags.data(),
+                       static_cast<int>(long_flags.size())));
+
     new_cmd_line.AppendSwitchPath(switches::kTestLauncherOutput, output_file);
-    new_cmd_line.AppendSwitchASCII(kGTestFilterFlag,
-                                   JoinString(test_names, ":"));
+    new_cmd_line.AppendSwitchPath(kGTestFlagfileFlag, temp_file);
     new_cmd_line.AppendSwitch(kSingleProcessTestsFlag);
 
     return new_cmd_line;
@@ -136,6 +147,8 @@
     }
   }
 
+  ScopedTempDir temp_dir_;
+
   DISALLOW_COPY_AND_ASSIGN(DefaultUnitTestPlatformDelegate);
 };
 
@@ -145,7 +158,7 @@
 
   std::string switch_value =
       CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name);
-  if (!StringToInt(switch_value, result) || *result < 1) {
+  if (!StringToInt(switch_value, result) || *result < 0) {
     LOG(ERROR) << "Invalid value for " << switch_name << ": " << switch_value;
     return false;
   }
@@ -155,6 +168,7 @@
 
 int LaunchUnitTestsInternal(const RunTestSuiteCallback& run_test_suite,
                             int default_jobs,
+                            int default_batch_limit,
                             bool use_job_objects,
                             const Closure& gtest_init) {
 #if defined(OS_ANDROID)
@@ -180,6 +194,8 @@
   if (CommandLine::ForCurrentProcess()->HasSwitch(kGTestHelpFlag) ||
       CommandLine::ForCurrentProcess()->HasSwitch(kGTestListTestsFlag) ||
       CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcessTestsFlag) ||
+      CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTestChildProcess) ||
       force_single_process) {
     return run_test_suite.Run();
   }
@@ -195,7 +211,7 @@
   gtest_init.Run();
   TestTimeouts::Initialize();
 
-  int batch_limit = kDefaultTestBatchLimit;
+  int batch_limit = default_batch_limit;
   if (!GetSwitchValueAsInt(switches::kTestLauncherBatchLimit, &batch_limit))
     return 1;
 
@@ -420,16 +436,40 @@
                     char** argv,
                     const RunTestSuiteCallback& run_test_suite) {
   CommandLine::Init(argc, argv);
-  return LaunchUnitTestsInternal(run_test_suite, SysInfo::NumberOfProcessors(),
-                                 true, Bind(&InitGoogleTestChar, &argc, argv));
+  return LaunchUnitTestsInternal(
+      run_test_suite,
+      SysInfo::NumberOfProcessors(),
+      kDefaultTestBatchLimit,
+      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));
+  return LaunchUnitTestsInternal(
+      run_test_suite,
+      1,
+      kDefaultTestBatchLimit,
+      true,
+      Bind(&InitGoogleTestChar, &argc, argv));
+}
+
+int LaunchUnitTestsWithOptions(
+    int argc,
+    char** argv,
+    int default_jobs,
+    int default_batch_limit,
+    bool use_job_objects,
+    const RunTestSuiteCallback& run_test_suite) {
+  CommandLine::Init(argc, argv);
+  return LaunchUnitTestsInternal(
+      run_test_suite,
+      default_jobs,
+      default_batch_limit,
+      use_job_objects,
+      Bind(&InitGoogleTestChar, &argc, argv));
 }
 
 #if defined(OS_WIN)
@@ -439,9 +479,12 @@
                     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));
+  return LaunchUnitTestsInternal(
+      run_test_suite,
+      SysInfo::NumberOfProcessors(),
+      kDefaultTestBatchLimit,
+      use_job_objects,
+      Bind(&InitGoogleTestWChar, &argc, argv));
 }
 #endif  // defined(OS_WIN)
 
@@ -537,7 +580,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 }
 
-bool UnitTestLauncherDelegate::GetTests(std::vector<SplitTestName>* output) {
+bool UnitTestLauncherDelegate::GetTests(std::vector<TestIdentifier>* output) {
   DCHECK(thread_checker_.CalledOnValidThread());
   return platform_delegate_->GetTests(output);
 }
diff --git a/base/test/launcher/unit_test_launcher.h b/base/test/launcher/unit_test_launcher.h
index ca00f10..83e5eaf 100644
--- a/base/test/launcher/unit_test_launcher.h
+++ b/base/test/launcher/unit_test_launcher.h
@@ -24,6 +24,19 @@
                             char** argv,
                             const RunTestSuiteCallback& run_test_suite);
 
+// Launches unit tests in given test suite. Returns exit code.
+// |default_jobs| is the default number of parallel test jobs.
+// |default_batch_limit| is the default size of test batch
+// (use 0 to disable batching).
+// |use_job_objects| determines whether to use job objects.
+int LaunchUnitTestsWithOptions(
+    int argc,
+    char** argv,
+    int default_jobs,
+    int default_batch_limit,
+    bool use_job_objects,
+    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.
@@ -38,7 +51,7 @@
  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;
+  virtual bool GetTests(std::vector<TestIdentifier>* output) = 0;
 
   // Called to create a temporary file. The delegate must put the resulting
   // path in |path| and return true on success.
@@ -86,7 +99,7 @@
 
  private:
   // TestLauncherDelegate:
-  bool GetTests(std::vector<SplitTestName>* output) override;
+  bool GetTests(std::vector<TestIdentifier>* output) override;
   bool ShouldRunTest(const std::string& test_case_name,
                      const std::string& test_name) override;
   size_t RunTests(TestLauncher* test_launcher,
diff --git a/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc b/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc
new file mode 100644
index 0000000..b2cf14a
--- /dev/null
+++ b/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/unit_test_launcher.h"
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/test/gtest_util.h"
+#include "base/test/gtest_xml_unittest_result_printer.h"
+#include "base/test/test_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite) {
+  CHECK(CommandLine::InitializedForCurrentProcess() ||
+        CommandLine::Init(argc, argv));
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTestLauncherListTests)) {
+    // Dump all test list into a file.
+    FilePath list_path(
+        command_line->GetSwitchValuePath(switches::kTestLauncherListTests));
+    if (!WriteCompiledInTestsToFile(list_path)) {
+      LOG(ERROR) << "Failed to write list of tests.";
+      return 1;
+    }
+
+    // Successfully done.
+    return 0;
+  }
+
+  // Register XML output printer, if --test-launcher-output flag is set.
+  if (command_line->HasSwitch(switches::kTestLauncherOutput)) {
+    FilePath output_path = command_line->GetSwitchValuePath(
+        switches::kTestLauncherOutput);
+    if (PathExists(output_path)) {
+      LOG(WARNING) << "Test launcher output path exists. Do not override";
+    } else {
+      XmlUnitTestResultPrinter* printer = new XmlUnitTestResultPrinter;
+      CHECK(printer->Initialize(output_path));
+      testing::UnitTest::GetInstance()->listeners().Append(printer);
+    }
+  }
+
+  return run_test_suite.Run();
+}
+
+}  // namespace base
diff --git a/base/test/sequenced_task_runner_test_template.h b/base/test/sequenced_task_runner_test_template.h
index c208d3c..31d05bc 100644
--- a/base/test/sequenced_task_runner_test_template.h
+++ b/base/test/sequenced_task_runner_test_template.h
@@ -2,9 +2,10 @@
 // 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.
+// SequencedTaskRunnerTest 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_
@@ -226,28 +227,6 @@
       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.
 //
@@ -326,16 +305,50 @@
 // whether the implementation supports nested tasks.
 //
 
+// The SequencedTaskRunnerTest test case verifies behaviour that is expected
+// from a sequenced task runner in order to be conformant.
 REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest,
                            SequentialNonNestable,
                            SequentialNestable,
                            SequentialDelayedNonNestable,
                            NonNestablePostFromNonNestableTask,
-                           DelayedTaskBasic,
                            DelayedTasksSameDelay,
                            DelayedTaskAfterLongTask,
                            DelayedTaskAfterManyLongTasks);
 
+template <typename TaskRunnerTestDelegate>
+class SequencedTaskRunnerDelayedTest
+    : public SequencedTaskRunnerTest<TaskRunnerTestDelegate> {};
+
+TYPED_TEST_CASE_P(SequencedTaskRunnerDelayedTest);
+
+// This test posts a delayed task, and checks that the task is run later than
+// the specified time.
+TYPED_TEST_P(SequencedTaskRunnerDelayedTest, 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);
+}
+
+// SequencedTaskRunnerDelayedTest tests that the |delay| parameter of
+// is used to actually wait for |delay| ms before executing the task.
+// This is not mandatory for a SequencedTaskRunner to be compliant.
+REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerDelayedTest, DelayedTaskBasic);
+
 }  // namespace base
 
 #endif  // BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/base/test/task_runner_test_template.h b/base/test/task_runner_test_template.h
index ee2b876..6022753 100644
--- a/base/test/task_runner_test_template.h
+++ b/base/test/task_runner_test_template.h
@@ -2,9 +2,9 @@
 // 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.
+// This file defines tests that implementations of TaskRunner should
+// pass in order to be conformant, as well as test cases for optional behavior.
+// 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
@@ -43,6 +43,13 @@
 //       MyTaskRunner, TaskRunnerTest, MyTaskRunnerTestDelegate);
 //
 // Easy!
+//
+// The optional test harnesses TaskRunnerAffinityTest can be
+// instanciated in the same way, using the same delegate:
+//
+//   INSTANTIATE_TYPED_TEST_CASE_P(
+//       MyTaskRunner, TaskRunnerAffinityTest, MyTaskRunnerTestDelegate);
+
 
 #ifndef BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
 #define BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
@@ -160,6 +167,10 @@
             this->task_tracker_->GetTaskRunCounts());
 }
 
+// The TaskRunnerTest test case verifies behaviour that is expected from a
+// task runner in order to be conformant.
+REGISTER_TYPED_TEST_CASE_P(TaskRunnerTest, Basic, Delayed);
+
 namespace internal {
 
 // Calls RunsTasksOnCurrentThread() on |task_runner| and expects it to
@@ -170,11 +181,16 @@
 
 }  // namespace internal
 
+template <typename TaskRunnerTestDelegate>
+class TaskRunnerAffinityTest : public TaskRunnerTest<TaskRunnerTestDelegate> {};
+
+TYPED_TEST_CASE_P(TaskRunnerAffinityTest);
+
 // 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) {
+TYPED_TEST_P(TaskRunnerAffinityTest, RunsTasksOnCurrentThread) {
   std::map<int, int> expected_task_run_counts;
 
   Thread thread("Non-task-runner thread");
@@ -209,8 +225,9 @@
             this->task_tracker_->GetTaskRunCounts());
 }
 
-REGISTER_TYPED_TEST_CASE_P(
-    TaskRunnerTest, Basic, Delayed, RunsTasksOnCurrentThread);
+// TaskRunnerAffinityTest tests that the TaskRunner implementation
+// can determine if tasks will never be run on a specific thread.
+REGISTER_TYPED_TEST_CASE_P(TaskRunnerAffinityTest, RunsTasksOnCurrentThread);
 
 }  // namespace base
 
diff --git a/base/test/test_discardable_memory_allocator.cc b/base/test/test_discardable_memory_allocator.cc
index 23d529c..eef1c98 100644
--- a/base/test/test_discardable_memory_allocator.cc
+++ b/base/test/test_discardable_memory_allocator.cc
@@ -20,6 +20,12 @@
   void Unlock() override {}
   void* data() const override { return data_.get(); }
 
+  trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump(
+      const char* name,
+      trace_event::ProcessMemoryDump* pmd) const override {
+    return nullptr;
+  }
+
  private:
   scoped_ptr<uint8_t[]> data_;
 };
diff --git a/base/test/test_file_util.cc b/base/test/test_file_util.cc
index 8dafc58..40b25f0 100644
--- a/base/test/test_file_util.cc
+++ b/base/test/test_file_util.cc
@@ -20,4 +20,9 @@
   return false;
 }
 
+// Declared in base/files/file_path.h.
+void PrintTo(const FilePath& path, std::ostream* out) {
+  *out << path.value();
+}
+
 }  // namespace base
diff --git a/base/test/test_file_util_android.cc b/base/test/test_file_util_android.cc
index b8fd50c..a272d67 100644
--- a/base/test/test_file_util_android.cc
+++ b/base/test/test_file_util_android.cc
@@ -4,6 +4,7 @@
 
 #include "base/test/test_file_util.h"
 
+#include "base/android/context_utils.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/files/file_path.h"
diff --git a/base/test/test_file_util_win.cc b/base/test/test_file_util_win.cc
index 5496a55..d2d6ac3 100644
--- a/base/test/test_file_util_win.cc
+++ b/base/test/test_file_util_win.cc
@@ -19,8 +19,6 @@
 
 namespace base {
 
-static const ptrdiff_t kOneMB = 1024 * 1024;
-
 namespace {
 
 struct PermissionInfo {
@@ -132,85 +130,21 @@
 }
 
 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.
+  // Re-write the file time information to trigger cache eviction for the file.
+  // This function previously overwrote the entire file without buffering, but
+  // local experimentation validates this simplified and *much* faster approach:
+  // [1] Sysinternals RamMap no longer lists these files as cached afterwards.
+  // [2] Telemetry performance test startup.cold.blank_page reports sane values.
   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;
 }
 
@@ -242,10 +176,8 @@
   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);
-
+  std::vector<std::string> lines = SplitString(
+      zone_path_contents, "\n", TRIM_WHITESPACE, SPLIT_WANT_ALL);
   switch (lines.size()) {
     case 3:
       // optional empty line at end of file:
diff --git a/base/test/test_pending_task_unittest.cc b/base/test/test_pending_task_unittest.cc
index 32502f2..7623ce4 100644
--- a/base/test/test_pending_task_unittest.cc
+++ b/base/test/test_pending_task_unittest.cc
@@ -10,7 +10,7 @@
 #include "testing/gtest/include/gtest/gtest-spi.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace {
+namespace base {
 
 TEST(TestPendingTaskTest, TraceSupport) {
   base::TestPendingTask task;
@@ -52,4 +52,4 @@
       << task_first << ".ShouldRunBefore(" << task_after << ")\n";
 }
 
-}  // namespace
+}  // namespace base
diff --git a/base/test/test_reg_util_win.cc b/base/test/test_reg_util_win.cc
index e3b1ffc..a7d07f7 100644
--- a/base/test/test_reg_util_win.cc
+++ b/base/test/test_reg_util_win.cc
@@ -7,6 +7,7 @@
 #include "base/guid.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/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -32,8 +33,10 @@
                                                         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))
+    std::vector<base::string16> tokens = base::SplitString(
+        key_name, kTimestampDelimiter, base::KEEP_WHITESPACE,
+        base::SPLIT_WANT_NONEMPTY);
+    if (tokens.empty())
       continue;
     int64 key_name_as_number = 0;
 
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index 6c766eb..57f4241 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -11,13 +11,16 @@
 #include "base/command_line.h"
 #include "base/debug/debugger.h"
 #include "base/debug/stack_trace.h"
+#include "base/feature_list.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/launch.h"
 #include "base/process/memory.h"
+#include "base/test/gtest_xml_unittest_result_printer.h"
 #include "base/test/gtest_xml_util.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/multiprocess_test.h"
@@ -225,8 +228,16 @@
 #if defined(OS_IOS)
   test_listener_ios::RegisterTestEndListener();
 #endif
+
+  // Set up a FeatureList instance, so that code using that API will not hit a
+  // an error that it's not set. Cleared by ClearInstanceForTesting() below.
+  base::FeatureList::SetInstance(make_scoped_ptr(new base::FeatureList));
+
   int result = RUN_ALL_TESTS();
 
+  // Clear the FeatureList that was registered above.
+  FeatureList::ClearInstanceForTesting();
+
 #if defined(OS_MACOSX)
   // This MUST happen before Shutdown() since Shutdown() tears down
   // objects (such as NotificationService::current()) that Cocoa
@@ -311,6 +322,7 @@
 
   CHECK(debug::EnableInProcessStackDumping());
 #if defined(OS_WIN)
+  RouteStdioToConsole(true);
   // Make sure we run with high resolution timer to minimize differences
   // between production code and test code.
   Time::EnableHighResolutionTimer(true);
@@ -337,7 +349,7 @@
   i18n::SetICUDefaultLocale("en_US");
 #else
   std::string default_locale(uloc_getDefault());
-  if (EndsWith(default_locale, "POSIX", false))
+  if (EndsWith(default_locale, "POSIX", CompareCase::INSENSITIVE_ASCII))
     i18n::SetICUDefaultLocale("en_US");
 #endif
 #endif
diff --git a/base/test/test_support_android.cc b/base/test/test_support_android.cc
index 11a0871..a0f825c 100644
--- a/base/test/test_support_android.cc
+++ b/base/test/test_support_android.cc
@@ -39,9 +39,7 @@
 // when there are no pending messages.
 class Waitable {
  public:
-   static Waitable* GetInstance() {
-     return Singleton<Waitable>::get();
-   }
+  static Waitable* GetInstance() { return base::Singleton<Waitable>::get(); }
 
    // Signals that there are more work to do.
    void Signal() {
@@ -59,7 +57,7 @@
    }
 
  private:
-  friend struct DefaultSingletonTraits<Waitable>;
+  friend struct base::DefaultSingletonTraits<Waitable>;
 
   Waitable()
       : waitable_event_(false, false) {
diff --git a/base/test/test_support_ios.mm b/base/test/test_support_ios.mm
index 3b31da6..9e82612 100644
--- a/base/test/test_support_ios.mm
+++ b/base/test/test_support_ios.mm
@@ -80,6 +80,10 @@
   label.textAlignment = NSTextAlignmentCenter;
   [window_ addSubview:label];
 
+  // An NSInternalInconsistencyException is thrown if the app doesn't have a
+  // root view controller. Set an empty one here.
+  [window_ setRootViewController:[[[UIViewController alloc] init] autorelease]];
+
   if ([self shouldRedirectOutputToFile])
     [self redirectOutput];
 
diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc
index 84aa53c..40f20d7 100644
--- a/base/test/test_switches.cc
+++ b/base/test/test_switches.cc
@@ -18,6 +18,11 @@
 const char switches::kTestLauncherDebugLauncher[] =
     "test-launcher-debug-launcher";
 
+// Force running all requested tests and retries even if too many test errors
+// occur.
+const char switches::kTestLauncherForceRunBrokenTests[] =
+    "test-launcher-force-run-broken-tests";
+
 // Path to file containing test filter (one pattern per line).
 const char switches::kTestLauncherFilterFile[] = "test-launcher-filter-file";
 
diff --git a/base/test/test_switches.h b/base/test/test_switches.h
index f145f1e..419b755 100644
--- a/base/test/test_switches.h
+++ b/base/test/test_switches.h
@@ -12,6 +12,7 @@
 extern const char kTestLauncherBatchLimit[];
 extern const char kTestLauncherBotMode[];
 extern const char kTestLauncherDebugLauncher[];
+extern const char kTestLauncherForceRunBrokenTests[];
 extern const char kTestLauncherFilterFile[];
 extern const char kTestLauncherJobs[];
 extern const char kTestLauncherListTests[];
diff --git a/base/test/test_ui_thread_android.cc b/base/test/test_ui_thread_android.cc
new file mode 100644
index 0000000..6f19974
--- /dev/null
+++ b/base/test/test_ui_thread_android.cc
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "base/test/test_ui_thread_android.h"
+
+#include "jni/TestUiThread_jni.h"
+
+namespace base {
+
+void StartTestUiThreadLooper() {
+  Java_TestUiThread_loop(base::android::AttachCurrentThread());
+}
+
+bool RegisterTestUiThreadAndroid(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/test/test_ui_thread_android.h b/base/test/test_ui_thread_android.h
new file mode 100644
index 0000000..dfecbfe
--- /dev/null
+++ b/base/test/test_ui_thread_android.h
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_UI_THREAD_ANDROID_
+#define BASE_TEST_TEST_UI_THREAD_ANDROID_
+
+#include <jni.h>
+
+namespace base {
+
+// Set up a thread as the Chromium UI Thread, and run its looper. This is is
+// intended for C++ unit tests (e.g. the net unit tests) that don't run with the
+// UI thread as their main looper, but test code that, on Android, uses UI
+// thread events, so need a running UI thread.
+void StartTestUiThreadLooper();
+
+bool RegisterTestUiThreadAndroid(JNIEnv* env);
+}  // namespace base
+
+#endif  //  BASE_TEST_TEST_UI_THREAD_ANDROID_
diff --git a/base/test/thread_test_helper.cc b/base/test/thread_test_helper.cc
index 6a12190..f238cee 100644
--- a/base/test/thread_test_helper.cc
+++ b/base/test/thread_test_helper.cc
@@ -4,6 +4,8 @@
 
 #include "base/test/thread_test_helper.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/threading/thread_restrictions.h"
@@ -13,9 +15,8 @@
 ThreadTestHelper::ThreadTestHelper(
     scoped_refptr<SingleThreadTaskRunner> target_thread)
     : test_result_(false),
-      target_thread_(target_thread.Pass()),
-      done_event_(false, false) {
-}
+      target_thread_(std::move(target_thread)),
+      done_event_(false, false) {}
 
 bool ThreadTestHelper::Run() {
   if (!target_thread_->PostTask(
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
index 3de58e7..0a0ff7f 100644
--- a/base/test/trace_event_analyzer.cc
+++ b/base/test/trace_event_analyzer.cc
@@ -10,6 +10,7 @@
 
 #include "base/json/json_reader.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/strings/pattern.h"
 #include "base/values.h"
 
 namespace trace_analyzer {
@@ -321,17 +322,17 @@
   switch (operator_) {
     case OP_EQ:
       if (right().is_pattern_)
-        *result = MatchPattern(lhs, rhs);
+        *result = base::MatchPattern(lhs, rhs);
       else if (left().is_pattern_)
-        *result = MatchPattern(rhs, lhs);
+        *result = base::MatchPattern(rhs, lhs);
       else
         *result = (lhs == rhs);
       return true;
     case OP_NE:
       if (right().is_pattern_)
-        *result = !MatchPattern(lhs, rhs);
+        *result = !base::MatchPattern(lhs, rhs);
       else if (left().is_pattern_)
-        *result = !MatchPattern(rhs, lhs);
+        *result = !base::MatchPattern(rhs, lhs);
       else
         *result = (lhs != rhs);
       return true;
@@ -647,8 +648,7 @@
 
 bool ParseEventsFromJson(const std::string& json,
                          std::vector<TraceEvent>* output) {
-  scoped_ptr<base::Value> root;
-  root.reset(base::JSONReader::Read(json));
+  scoped_ptr<base::Value> root = base::JSONReader::Read(json);
 
   base::ListValue* root_list = NULL;
   if (!root.get() || !root->GetAsList(&root_list))
diff --git a/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc
index cf85fd0..6503b1f 100644
--- a/base/test/trace_event_analyzer_unittest.cc
+++ b/base/test/trace_event_analyzer_unittest.cc
@@ -6,6 +6,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/test/trace_event_analyzer.h"
 #include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_buffer.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -46,9 +47,8 @@
   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());
+      base::trace_event::TraceConfig("*", ""),
+      base::trace_event::TraceLog::RECORDING_MODE);
 }
 
 void TraceEventAnalyzerTest::EndTracing() {
diff --git a/base/test/trace_to_file.cc b/base/test/trace_to_file.cc
index 4e2a332..85fff71 100644
--- a/base/test/trace_to_file.cc
+++ b/base/test/trace_to_file.cc
@@ -9,7 +9,8 @@
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/run_loop.h"
-#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_log.h"
 
 namespace base {
 namespace test {
@@ -52,9 +53,8 @@
   WriteFileHeader();
 
   trace_event::TraceLog::GetInstance()->SetEnabled(
-      trace_event::CategoryFilter(categories),
-      trace_event::TraceLog::RECORDING_MODE,
-      trace_event::TraceOptions(trace_event::RECORD_UNTIL_FULL));
+      trace_event::TraceConfig(categories, trace_event::RECORD_UNTIL_FULL),
+      trace_event::TraceLog::RECORDING_MODE);
 }
 
 void TraceToFile::WriteFileHeader() {
diff --git a/base/test/values_test_util.cc b/base/test/values_test_util.cc
index 3e762b9..f974c14 100644
--- a/base/test/values_test_util.cc
+++ b/base/test/values_test_util.cc
@@ -64,14 +64,13 @@
 
 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));
+  scoped_ptr<Value> result = base::JSONReader::ReadAndReturnError(
+      json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error_msg);
   if (!result) {
     ADD_FAILURE() << "Failed to parse \"" << json << "\": " << error_msg;
     result = Value::CreateNullValue();
   }
-  return result.Pass();
+  return result;
 }
 
 }  // namespace test
diff --git a/base/third_party/dynamic_annotations/BUILD.gn b/base/third_party/dynamic_annotations/BUILD.gn
index bc324ae..86f6558 100644
--- a/base/third_party/dynamic_annotations/BUILD.gn
+++ b/base/third_party/dynamic_annotations/BUILD.gn
@@ -19,7 +19,7 @@
       "dynamic_annotations.h",
     ]
     if (is_android && !is_debug) {
-      configs -= [ "//build/config/compiler:optimize" ]
+      configs -= [ "//build/config/compiler:default_optimization" ]
       configs += [ "//build/config/compiler:optimize_max" ]
     }
   }
diff --git a/base/third_party/nspr/prtime.cc b/base/third_party/nspr/prtime.cc
index 9335b01..a7c5a3a 100644
--- a/base/third_party/nspr/prtime.cc
+++ b/base/third_party/nspr/prtime.cc
@@ -107,9 +107,9 @@
     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};
+    SYSTEMTIME st = {};
+    FILETIME ft = {};
+    ULARGE_INTEGER uli = {};
 
     st.wYear = exploded->tm_year;
     st.wMonth = static_cast<WORD>(exploded->tm_month + 1);
diff --git a/base/third_party/superfasthash/OWNERS b/base/third_party/superfasthash/OWNERS
index f34cfb1..633cc35 100644
--- a/base/third_party/superfasthash/OWNERS
+++ b/base/third_party/superfasthash/OWNERS
@@ -1,2 +1 @@
 mgiuca@chromium.org
-rvargas@chromium.org
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium
index de92794..64a6247 100644
--- a/base/third_party/symbolize/README.chromium
+++ b/base/third_party/symbolize/README.chromium
@@ -1,9 +1,10 @@
 Name: google-glog's symbolization library
-URL: http://code.google.com/p/google-glog/
+URL: https://github.com/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)
+https://github.com/google/glog/tree/a5ffa884137f7687d0393ccba22557d583654a25
 
 - demangle.cc
 - demangle.h
diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
index b25f747..f4861df 100644
--- a/base/third_party/symbolize/symbolize.cc
+++ b/base/third_party/symbolize/symbolize.cc
@@ -651,7 +651,8 @@
 
   // Handle negative numbers (only for base 10).
   if (i < 0 && base == 10) {
-    j = -i;
+    // This does "j = -i" while avoiding integer overflow.
+    j = static_cast<uintptr_t>(-(i + 1)) + 1;
 
     // Make sure we can write the '-' character.
     if (++n > sz) {
diff --git a/base/thread_task_runner_handle.cc b/base/thread_task_runner_handle.cc
index 860a0ec..ee337b3 100644
--- a/base/thread_task_runner_handle.cc
+++ b/base/thread_task_runner_handle.cc
@@ -12,7 +12,7 @@
 
 namespace {
 
-base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle> >
+base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle> >::Leaky
     lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
diff --git a/base/thread_task_runner_handle.h b/base/thread_task_runner_handle.h
index 238435f..197669e 100644
--- a/base/thread_task_runner_handle.h
+++ b/base/thread_task_runner_handle.h
@@ -16,6 +16,7 @@
 // in thread-local storage.  Callers can then retrieve the TaskRunner
 // for the current thread by calling ThreadTaskRunnerHandle::Get().
 // At most one TaskRunner may be bound to each thread at a time.
+// Prefer SequenceTaskRunnerHandle to this unless thread affinity is required.
 class BASE_EXPORT ThreadTaskRunnerHandle {
  public:
   // Gets the SingleThreadTaskRunner for the current thread.
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
index d8f06e5..6b52cc4 100644
--- a/base/threading/platform_thread.h
+++ b/base/threading/platform_thread.h
@@ -73,21 +73,9 @@
   typedef pthread_t Handle;
 #endif
 
-  PlatformThreadHandle()
-      : handle_(0),
-        id_(0) {
-  }
+  PlatformThreadHandle() : handle_(0) {}
 
-  explicit PlatformThreadHandle(Handle handle)
-      : handle_(handle),
-        id_(0) {
-  }
-
-  PlatformThreadHandle(Handle handle,
-                       PlatformThreadId id)
-      : handle_(handle),
-        id_(id) {
-  }
+  explicit PlatformThreadHandle(Handle handle) : handle_(handle) {}
 
   bool is_equal(const PlatformThreadHandle& other) const {
     return handle_ == other.handle_;
@@ -102,16 +90,13 @@
   }
 
  private:
-  friend class PlatformThread;
-
   Handle handle_;
-  PlatformThreadId id_;
 };
 
 const PlatformThreadId kInvalidThreadId(0);
 
-// Valid values for SetThreadPriority(), listed in increasing order of
-// importance.
+// Valid values for priority of Thread::Options and SimpleThread::Options, and
+// SetCurrentThreadPriority(), listed in increasing order of importance.
 enum class ThreadPriority {
   // Suitable for threads that shouldn't disrupt high priority work.
   BACKGROUND,
@@ -170,12 +155,15 @@
   // 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);
+  static bool Create(size_t stack_size,
+                     Delegate* delegate,
+                     PlatformThreadHandle* thread_handle) {
+    return CreateWithPriority(stack_size, delegate, thread_handle,
+                              ThreadPriority::NORMAL);
+  }
 
   // CreateWithPriority() does the same thing as Create() except the priority of
-  // the thread is set based on |priority|.  Can be used in place of Create()
-  // followed by SetThreadPriority().
+  // the thread is set based on |priority|.
   static bool CreateWithPriority(size_t stack_size, Delegate* delegate,
                                  PlatformThreadHandle* thread_handle,
                                  ThreadPriority priority);
@@ -190,10 +178,15 @@
   // |thread_handle|.
   static void Join(PlatformThreadHandle thread_handle);
 
-  static void SetThreadPriority(PlatformThreadHandle handle,
-                                ThreadPriority priority);
+  // Toggles the current thread's priority at runtime. A thread may not be able
+  // to raise its priority back up after lowering it if the process does not
+  // have a proper permission, e.g. CAP_SYS_NICE on Linux.
+  // Since changing other threads' priority is not permitted in favor of
+  // security, this interface is restricted to change only the current thread
+  // priority (https://crbug.com/399473).
+  static void SetCurrentThreadPriority(ThreadPriority priority);
 
-  static ThreadPriority GetThreadPriority(PlatformThreadHandle handle);
+  static ThreadPriority GetCurrentThreadPriority();
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc
index 11e5e2e..b6bea49 100644
--- a/base/threading/platform_thread_android.cc
+++ b/base/threading/platform_thread_android.cc
@@ -23,29 +23,21 @@
 
 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).
+// - BACKGROUND is 9 due to it being the nicest value we can use that's still
+// above an Android system threshold that enables heavy throttling starting at
+// 10; we want to be lower-priority than Chrome's other threads without
+// incurring this behavior.
+// - DISPLAY is -6 due to being midway between Android's DISPLAY (-4) and
+// URGENT_DISPLAY (-8).
+// - REALTIME_AUDIO corresponds to Android's THREAD_PRIORITY_AUDIO = -16 value.
 const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
-    {ThreadPriority::BACKGROUND, 10},
+    {ThreadPriority::BACKGROUND, 9},
     {ThreadPriority::NORMAL, 0},
     {ThreadPriority::DISPLAY, -6},
     {ThreadPriority::REALTIME_AUDIO, -16},
 };
 
-bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority priority) {
+bool SetCurrentThreadPriorityForPlatform(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) {
@@ -56,9 +48,15 @@
   return false;
 }
 
-bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority* priority) {
-  NOTIMPLEMENTED();
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) {
+  DCHECK(priority);
+  *priority = ThreadPriority::NORMAL;
+  JNIEnv* env = base::android::AttachCurrentThread();
+  if (Java_ThreadUtils_isThreadPriorityAudio(
+      env, PlatformThread::CurrentId())) {
+    *priority = ThreadPriority::REALTIME_AUDIO;
+    return true;
+  }
   return false;
 }
 
@@ -88,8 +86,7 @@
 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);
+  PlatformThread::SetCurrentThreadPriority(ThreadPriority::NORMAL);
 }
 
 void TerminateOnThread() {
diff --git a/base/threading/platform_thread_freebsd.cc b/base/threading/platform_thread_freebsd.cc
index f4fded0..e29e865 100644
--- a/base/threading/platform_thread_freebsd.cc
+++ b/base/threading/platform_thread_freebsd.cc
@@ -36,11 +36,8 @@
     {ThreadPriority::REALTIME_AUDIO, -10},
 }
 
-bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority priority) {
+bool SetCurrentThreadPriorityForPlatform(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
@@ -48,11 +45,8 @@
 #endif
 }
 
-bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority* priority) {
+bool GetCurrentThreadPriorityForPlatform(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,
diff --git a/base/threading/platform_thread_internal_posix.h b/base/threading/platform_thread_internal_posix.h
index 62006ce..05a8d1e 100644
--- a/base/threading/platform_thread_internal_posix.h
+++ b/base/threading/platform_thread_internal_posix.h
@@ -26,17 +26,15 @@
 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);
+// SetCurrentThreadPriority. Returns true if the platform-specific
+// implementation handled this |priority| change, false if the generic
+// implementation should instead proceed.
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority);
 
-// Returns true if there is a platform-specific ThreadPriority set on |handle|
-// (and returns the actual ThreadPriority via |priority|). Returns false
-// otherwise, leaving |priority| untouched.
-bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority* priority);
+// Returns true if there is a platform-specific ThreadPriority set on the
+// current thread (and returns the actual ThreadPriority via |priority|).
+// Returns false otherwise, leaving |priority| untouched.
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority);
 
 }  // namespace internal
 
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
index 9f74374..48cf744 100644
--- a/base/threading/platform_thread_linux.cc
+++ b/base/threading/platform_thread_linux.cc
@@ -27,6 +27,7 @@
 namespace {
 #if !defined(OS_NACL)
 const struct sched_param kRealTimePrio = {8};
+const struct sched_param kResetPrio = {0};
 #endif
 }  // namespace
 
@@ -37,11 +38,18 @@
     {ThreadPriority::REALTIME_AUDIO, -10},
 };
 
-bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority priority) {
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
 #if !defined(OS_NACL)
-  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
-  // of |handle|. http://crbug.com/468793.
+  ThreadPriority current_priority;
+  if (priority != ThreadPriority::REALTIME_AUDIO &&
+      GetCurrentThreadPriorityForPlatform(&current_priority) &&
+      current_priority == ThreadPriority::REALTIME_AUDIO) {
+    // If the pthread's round-robin scheduler is already enabled, and the new
+    // priority will use setpriority() instead, the pthread scheduler should be
+    // reset to use SCHED_OTHER so that setpriority() just works.
+    pthread_setschedparam(pthread_self(), SCHED_OTHER, &kResetPrio);
+    return false;
+  }
   return priority == ThreadPriority::REALTIME_AUDIO  &&
          pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
 #else
@@ -49,13 +57,10 @@
 #endif
 }
 
-bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
-                                  ThreadPriority* priority) {
+bool GetCurrentThreadPriorityForPlatform(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 &&
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
index a9c347a..1ecbcd6 100644
--- a/base/threading/platform_thread_mac.mm
+++ b/base/threading/platform_thread_mac.mm
@@ -155,10 +155,10 @@
 }  // anonymous namespace
 
 // static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
-                                       ThreadPriority priority) {
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
   // Convert from pthread_t to mach thread identifier.
-  mach_port_t mach_thread_id = pthread_mach_thread_np(handle.handle_);
+  mach_port_t mach_thread_id =
+      pthread_mach_thread_np(PlatformThread::CurrentHandle().platform_handle());
 
   switch (priority) {
     case ThreadPriority::NORMAL:
@@ -174,7 +174,7 @@
 }
 
 // static
-ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
   NOTIMPLEMENTED();
   return ThreadPriority::NORMAL;
 }
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 3dbdc98..0adb92d 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -13,12 +13,9 @@
 #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>
@@ -37,39 +34,29 @@
 
 struct ThreadParams {
   ThreadParams()
-      : delegate(NULL),
-        joinable(false),
-        priority(ThreadPriority::NORMAL),
-        handle(NULL),
-        handle_set(false, false) {
-  }
+      : delegate(NULL), joinable(false), priority(ThreadPriority::NORMAL) {}
 
   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);
+  PlatformThread::Delegate* delegate = nullptr;
 
-  if (thread_params->priority != ThreadPriority::NORMAL) {
-    PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
-                                      thread_params->priority);
+  {
+    scoped_ptr<ThreadParams> thread_params(static_cast<ThreadParams*>(params));
+
+    delegate = thread_params->delegate;
+    if (!thread_params->joinable)
+      base::ThreadRestrictions::SetSingletonAllowed(false);
+
+    if (thread_params->priority != ThreadPriority::NORMAL)
+      PlatformThread::SetCurrentThreadPriority(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());
@@ -84,21 +71,21 @@
   return NULL;
 }
 
-bool CreateThread(size_t stack_size, bool joinable,
+bool CreateThread(size_t stack_size,
+                  bool joinable,
                   PlatformThread::Delegate* delegate,
                   PlatformThreadHandle* thread_handle,
                   ThreadPriority priority) {
+  DCHECK(thread_handle);
   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) {
+  if (!joinable)
     pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
-  }
 
   // Get a better default if available.
   if (stack_size == 0)
@@ -107,33 +94,27 @@
   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;
+  scoped_ptr<ThreadParams> params(new ThreadParams);
+  params->delegate = delegate;
+  params->joinable = joinable;
+  params->priority = priority;
 
   pthread_t handle;
-  int err = pthread_create(&handle,
-                           &attributes,
-                           ThreadFunc,
-                           &params);
-  success = !err;
-  if (!success) {
+  int err = pthread_create(&handle, &attributes, ThreadFunc, params.get());
+  bool success = !err;
+  if (success) {
+    // ThreadParams should be deleted on the created thread after used.
+    ignore_result(params.release());
+  } else {
     // Value of |handle| is undefined if pthread_create fails.
     handle = 0;
     errno = err;
     PLOG(ERROR) << "pthread_create";
   }
+  *thread_handle = PlatformThreadHandle(handle);
 
   pthread_attr_destroy(&attributes);
 
-  // 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;
 }
 
@@ -168,7 +149,7 @@
 
 // static
 PlatformThreadHandle PlatformThread::CurrentHandle() {
-  return PlatformThreadHandle(pthread_self(), CurrentId());
+  return PlatformThreadHandle(pthread_self());
 }
 
 // static
@@ -197,18 +178,9 @@
 }
 
 // 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);
 }
@@ -217,7 +189,6 @@
 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;
@@ -229,19 +200,18 @@
   // 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));
+  CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), NULL));
 }
 
-// Mac has its own Set/GetThreadPriority() implementations.
+// Mac has its own Set/GetCurrentThreadPriority() implementations.
 #if !defined(OS_MACOSX)
 
 // static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
-                                       ThreadPriority priority) {
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
 #if defined(OS_NACL)
   NOTIMPLEMENTED();
 #else
-  if (internal::SetThreadPriorityForPlatform(handle, priority))
+  if (internal::SetCurrentThreadPriorityForPlatform(priority))
     return;
 
   // setpriority(2) should change the whole thread group's (i.e. process)
@@ -250,39 +220,34 @@
   // 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;
+  if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
+    DVPLOG(1) << "Failed to set nice value of thread ("
+              << PlatformThread::CurrentId() << ") to " << nice_setting;
   }
 #endif  // defined(OS_NACL)
 }
 
 // static
-ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
 #if defined(OS_NACL)
   NOTIMPLEMENTED();
   return ThreadPriority::NORMAL;
 #else
-  // Mirrors SetThreadPriority()'s implementation.
+  // Mirrors SetCurrentThreadPriority()'s implementation.
   ThreadPriority platform_specific_priority;
-  if (internal::GetThreadPriorityForPlatform(handle,
-                                             &platform_specific_priority)) {
+  if (internal::GetCurrentThreadPriorityForPlatform(
+          &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_);
+  int nice_value = getpriority(PRIO_PROCESS, 0);
   if (errno != 0) {
-    DVPLOG(1) << "Failed to get nice value of thread (" << handle.id_ << ")";
+    DVPLOG(1) << "Failed to get nice value of thread ("
+              << PlatformThread::CurrentId() << ")";
     return ThreadPriority::NORMAL;
   }
 
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
index c4b3d5d..1ac08a7 100644
--- a/base/threading/platform_thread_unittest.cc
+++ b/base/threading/platform_thread_unittest.cc
@@ -8,7 +8,10 @@
 #include "base/threading/platform_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_WIN)
+#if defined(OS_POSIX)
+#include <sys/types.h>
+#include <unistd.h>
+#elif defined(OS_WIN)
 #include <windows.h>
 #endif
 
@@ -16,6 +19,8 @@
 
 // Trivial tests that thread runs and doesn't crash on create and join ---------
 
+namespace {
+
 class TrivialThread : public PlatformThread::Delegate {
  public:
   TrivialThread() : did_run_(false) {}
@@ -30,6 +35,8 @@
   DISALLOW_COPY_AND_ASSIGN(TrivialThread);
 };
 
+}  // namespace
+
 TEST(PlatformThreadTest, Trivial) {
   TrivialThread thread;
   PlatformThreadHandle handle;
@@ -56,11 +63,13 @@
 
 // Tests of basic thread functions ---------------------------------------------
 
+namespace {
+
 class FunctionTestThread : public PlatformThread::Delegate {
  public:
   FunctionTestThread()
       : thread_id_(kInvalidThreadId),
-        thread_started_(true, false),
+        termination_ready_(true, false),
         terminate_thread_(true, false),
         done_(false) {}
   ~FunctionTestThread() override {
@@ -70,8 +79,9 @@
         << "WaitableEvent blocking the underlying thread's main.";
   }
 
-  // Grabs |thread_id_|, signals |thread_started_|, and then waits for
-  // |terminate_thread_| to be signaled before exiting.
+  // Grabs |thread_id_|, runs an optional test on that thread, signals
+  // |termination_ready_|, and then waits for |terminate_thread_| to be
+  // signaled before exiting.
   void ThreadMain() override {
     thread_id_ = PlatformThread::CurrentId();
     EXPECT_NE(thread_id_, kInvalidThreadId);
@@ -79,39 +89,46 @@
     // Make sure that the thread ID is the same across calls.
     EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
 
-    thread_started_.Signal();
+    // Run extra tests.
+    RunTest();
 
+    termination_ready_.Signal();
     terminate_thread_.Wait();
 
     done_ = true;
   }
 
   PlatformThreadId thread_id() const {
-    EXPECT_TRUE(thread_started_.IsSignaled()) << "Thread ID still unknown";
+    EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
     return thread_id_;
   }
 
   bool IsRunning() const {
-    return thread_started_.IsSignaled() && !done_;
+    return termination_ready_.IsSignaled() && !done_;
   }
 
-  // Blocks until this thread is started.
-  void WaitForThreadStart() { thread_started_.Wait(); }
+  // Blocks until this thread is started and ready to be terminated.
+  void WaitForTerminationReady() { termination_ready_.Wait(); }
 
-  // Mark this thread for termination (callers must then join this thread to be
+  // Marks this thread for termination (callers must then join this thread to be
   // guaranteed of termination).
   void MarkForTermination() { terminate_thread_.Signal(); }
 
  private:
+  // Runs an optional test on the newly created thread.
+  virtual void RunTest() {}
+
   PlatformThreadId thread_id_;
 
-  mutable WaitableEvent thread_started_;
+  mutable WaitableEvent termination_ready_;
   WaitableEvent terminate_thread_;
   bool done_;
 
   DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
 };
 
+}  // namespace
+
 TEST(PlatformThreadTest, Function) {
   PlatformThreadId main_thread_id = PlatformThread::CurrentId();
 
@@ -120,7 +137,7 @@
 
   ASSERT_FALSE(thread.IsRunning());
   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-  thread.WaitForThreadStart();
+  thread.WaitForTerminationReady();
   ASSERT_TRUE(thread.IsRunning());
   EXPECT_NE(thread.thread_id(), main_thread_id);
 
@@ -144,7 +161,7 @@
   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();
+    thread[n].WaitForTerminationReady();
 
   for (size_t n = 0; n < arraysize(thread); n++) {
     ASSERT_TRUE(thread[n].IsRunning());
@@ -170,106 +187,86 @@
 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,
+// The order should be higher to lower to cover as much cases as possible on
+// Linux trybots running without CAP_SYS_NICE permission.
+#if !defined(OS_ANDROID)
+    // PlatformThread::GetCurrentThreadPriority() on Android does not support
+    // REALTIME_AUDIO case. See http://crbug.com/505474.
     ThreadPriority::REALTIME_AUDIO,
-    // Keep BACKGROUND second to last to test backgrounding from other
-    // priorities.
+#endif
+    ThreadPriority::DISPLAY,
+    // This redundant BACKGROUND priority is to test backgrounding from other
+    // priorities, and unbackgrounding.
     ThreadPriority::BACKGROUND,
-#endif  // !defined(OS_POSIX)
-    // Keep NORMAL last to test unbackgrounding.
-    ThreadPriority::NORMAL
+    ThreadPriority::NORMAL,
+    ThreadPriority::BACKGROUND};
+
+bool IsBumpingPriorityAllowed() {
+#if defined(OS_POSIX)
+  // Only root can raise thread priority on POSIX environment. On Linux, users
+  // who have CAP_SYS_NICE permission also can raise the thread priority, but
+  // libcap.so would be needed to check the capability.
+  return geteuid() == 0;
+#else
+  return true;
+#endif
+}
+
+class ThreadPriorityTestThread : public FunctionTestThread {
+ public:
+  ThreadPriorityTestThread() = default;
+  ~ThreadPriorityTestThread() override = default;
+
+ private:
+  void RunTest() override {
+    // Confirm that the current thread's priority is as expected.
+    EXPECT_EQ(ThreadPriority::NORMAL,
+              PlatformThread::GetCurrentThreadPriority());
+
+    // Toggle each supported priority on the current thread and confirm it
+    // affects it.
+    const bool bumping_priority_allowed = IsBumpingPriorityAllowed();
+    for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+      SCOPED_TRACE(i);
+      if (!bumping_priority_allowed &&
+          kThreadPriorityTestValues[i] >
+              PlatformThread::GetCurrentThreadPriority()) {
+        continue;
+      }
+
+      // Alter and verify the current thread's priority.
+      PlatformThread::SetCurrentThreadPriority(kThreadPriorityTestValues[i]);
+      EXPECT_EQ(kThreadPriorityTestValues[i],
+                PlatformThread::GetCurrentThreadPriority());
+    }
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread);
 };
 
 }  // 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());
+#if defined(OS_MACOSX)
+// PlatformThread::GetCurrentThreadPriority() is not implemented on OS X.
+#define MAYBE_ThreadPriorityCurrentThread DISABLED_ThreadPriorityCurrentThread
+#else
+#define MAYBE_ThreadPriorityCurrentThread ThreadPriorityCurrentThread
+#endif
 
-  // 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
+// Test changing a created 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;
+TEST(PlatformThreadTest, MAYBE_ThreadPriorityCurrentThread) {
+  ThreadPriorityTestThread thread;
   PlatformThreadHandle handle;
+
+  ASSERT_FALSE(thread.IsRunning());
   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.WaitForTerminationReady();
+  ASSERT_TRUE(thread.IsRunning());
 
   thread.MarkForTermination();
   PlatformThread::Join(handle);
+  ASSERT_FALSE(thread.IsRunning());
 }
 
 }  // namespace base
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index 4eb2cb2..25973bc 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -46,6 +46,7 @@
 struct ThreadParams {
   PlatformThread::Delegate* delegate;
   bool joinable;
+  ThreadPriority priority;
 };
 
 DWORD __stdcall ThreadFunc(void* params) {
@@ -54,6 +55,9 @@
   if (!thread_params->joinable)
     base::ThreadRestrictions::SetSingletonAllowed(false);
 
+  if (thread_params->priority != ThreadPriority::NORMAL)
+    PlatformThread::SetCurrentThreadPriority(thread_params->priority);
+
   // Retrieve a copy of the thread handle to use as the key in the
   // thread name mapping.
   PlatformThreadHandle::Handle platform_handle;
@@ -83,15 +87,16 @@
         PlatformThread::CurrentId());
   }
 
-  return NULL;
+  return 0;
 }
 
-// CreateThreadInternal() matches PlatformThread::Create(), except that
-// |out_thread_handle| may be NULL, in which case a non-joinable thread is
-// created.
+// CreateThreadInternal() matches PlatformThread::CreateWithPriority(), except
+// that |out_thread_handle| may be nullptr, in which case a non-joinable thread
+// is created.
 bool CreateThreadInternal(size_t stack_size,
                           PlatformThread::Delegate* delegate,
-                          PlatformThreadHandle* out_thread_handle) {
+                          PlatformThreadHandle* out_thread_handle,
+                          ThreadPriority priority) {
   unsigned int flags = 0;
   if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
     flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
@@ -101,15 +106,16 @@
 
   ThreadParams* params = new ThreadParams;
   params->delegate = delegate;
-  params->joinable = out_thread_handle != NULL;
+  params->joinable = out_thread_handle != nullptr;
+  params->priority = priority;
 
   // 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);
+  void* thread_handle =
+      ::CreateThread(nullptr, stack_size, ThreadFunc, params, flags, nullptr);
   if (!thread_handle) {
     delete params;
     return false;
@@ -182,30 +188,22 @@
 }
 
 // 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;
+  DCHECK(thread_handle);
+  return CreateThreadInternal(stack_size, delegate, thread_handle, priority);
 }
 
 // static
 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
-  return CreateThreadInternal(stack_size, delegate, NULL);
+  return CreateThreadInternal(stack_size, delegate, nullptr,
+                              ThreadPriority::NORMAL);
 }
 
 // static
 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
-  DCHECK(thread_handle.handle_);
+  DCHECK(thread_handle.platform_handle());
   // TODO(willchan): Enable this check once I can get it to work for Windows
   // shutdown.
   // Joining another thread may block the current thread for a long time, since
@@ -217,24 +215,20 @@
 
   // 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);
+  DWORD result = WaitForSingleObject(thread_handle.platform_handle(), INFINITE);
   if (result != WAIT_OBJECT_0) {
     // Debug info for bug 127931.
     DWORD error = GetLastError();
     debug::Alias(&error);
     debug::Alias(&result);
-    debug::Alias(&thread_handle.handle_);
     CHECK(false);
   }
 
-  CloseHandle(thread_handle.handle_);
+  CloseHandle(thread_handle.platform_handle());
 }
 
 // static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
-                                       ThreadPriority priority) {
-  DCHECK(!handle.is_null());
-
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
   int desired_priority = THREAD_PRIORITY_ERROR_RETURN;
   switch (priority) {
     case ThreadPriority::BACKGROUND:
@@ -258,16 +252,16 @@
 #ifndef NDEBUG
   const BOOL success =
 #endif
-      ::SetThreadPriority(handle.handle_, desired_priority);
+      ::SetThreadPriority(PlatformThread::CurrentHandle().platform_handle(),
+                          desired_priority);
   DPLOG_IF(ERROR, !success) << "Failed to set thread priority to "
                             << desired_priority;
 }
 
 // static
-ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
-  DCHECK(!handle.is_null());
-
-  int priority = ::GetThreadPriority(handle.handle_);
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
+  int priority =
+      ::GetThreadPriority(PlatformThread::CurrentHandle().platform_handle());
   switch (priority) {
     case THREAD_PRIORITY_LOWEST:
       return ThreadPriority::BACKGROUND;
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
index f3e88ab..80ca520 100644
--- a/base/threading/post_task_and_reply_impl.cc
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -75,6 +75,9 @@
     const tracked_objects::Location& from_here,
     const Closure& task,
     const Closure& reply) {
+  // TODO(tzik): Use DCHECK here once the crash is gone. http://crbug.com/541319
+  CHECK(!task.is_null()) << from_here.ToString();
+  CHECK(!reply.is_null()) << from_here.ToString();
   PostTaskAndReplyRelay* relay =
       new PostTaskAndReplyRelay(from_here, task, reply);
   if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
diff --git a/base/threading/post_task_and_reply_impl.h b/base/threading/post_task_and_reply_impl.h
index a5b9580..d21ab78 100644
--- a/base/threading/post_task_and_reply_impl.h
+++ b/base/threading/post_task_and_reply_impl.h
@@ -25,6 +25,8 @@
 // may want base::WorkerPool.
 class PostTaskAndReplyImpl {
  public:
+  virtual ~PostTaskAndReplyImpl() = default;
+
   // Implementation for TaskRunner::PostTaskAndReply and
   // WorkerPool::PostTaskAndReply.
   bool PostTaskAndReply(const tracked_objects::Location& from_here,
diff --git a/base/threading/sequenced_task_runner_handle.cc b/base/threading/sequenced_task_runner_handle.cc
new file mode 100644
index 0000000..a03642d
--- /dev/null
+++ b/base/threading/sequenced_task_runner_handle.cc
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/sequenced_task_runner_handle.h"
+
+#include "base/sequenced_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/sequenced_worker_pool.h"
+
+namespace base {
+
+// static
+scoped_refptr<SequencedTaskRunner> SequencedTaskRunnerHandle::Get() {
+  // If we are on a worker thread for a SequencedBlockingPool that is running a
+  // sequenced task, return a SequencedTaskRunner for it.
+  scoped_refptr<base::SequencedWorkerPool> pool =
+      SequencedWorkerPool::GetWorkerPoolForCurrentThread();
+  if (pool) {
+    SequencedWorkerPool::SequenceToken sequence_token =
+        SequencedWorkerPool::GetSequenceTokenForCurrentThread();
+    DCHECK(sequence_token.IsValid());
+    DCHECK(pool->IsRunningSequenceOnCurrentThread(sequence_token));
+    return pool->GetSequencedTaskRunner(sequence_token);
+  }
+
+  // Otherwise, return a SingleThreadTaskRunner for the current thread.
+  return base::ThreadTaskRunnerHandle::Get();
+}
+
+// static
+bool SequencedTaskRunnerHandle::IsSet() {
+  return (SequencedWorkerPool::GetWorkerPoolForCurrentThread() &&
+          SequencedWorkerPool::GetSequenceTokenForCurrentThread().IsValid()) ||
+         base::ThreadTaskRunnerHandle::IsSet();
+}
+
+}  // namespace base
diff --git a/base/threading/sequenced_task_runner_handle.h b/base/threading/sequenced_task_runner_handle.h
new file mode 100644
index 0000000..c638d2f
--- /dev/null
+++ b/base/threading/sequenced_task_runner_handle.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_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
+#define BASE_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+class SequencedTaskRunner;
+
+class BASE_EXPORT SequencedTaskRunnerHandle {
+ public:
+  // Returns a SequencedTaskRunner which guarantees that posted tasks will only
+  // run after the current task is finished and will satisfy a SequenceChecker.
+  // It should only be called if IsSet() returns true (see the comment there for
+  // the requirements).
+  static scoped_refptr<SequencedTaskRunner> Get();
+
+  // Returns true if one of the following conditions is fulfilled:
+  // a) The current thread has a ThreadTaskRunnerHandle (which includes any
+  //    thread that has a MessageLoop associated with it), or
+  // b) The current thread is a worker thread belonging to a SequencedWorkerPool
+  //    *and* is currently running a sequenced task.
+  static bool IsSet();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SequencedTaskRunnerHandle);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
diff --git a/base/threading/sequenced_task_runner_handle_unittest.cc b/base/threading/sequenced_task_runner_handle_unittest.cc
new file mode 100644
index 0000000..1080262
--- /dev/null
+++ b/base/threading/sequenced_task_runner_handle_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/bind.h"
+#include "base/callback.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/run_loop.h"
+#include "base/sequence_checker_impl.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class SequencedTaskRunnerHandleTest : public ::testing::Test {
+ protected:
+  static void GetTaskRunner(const Closure& callback) {
+    // Use SequenceCheckerImpl to make sure it's not a no-op in Release builds.
+    scoped_ptr<SequenceCheckerImpl> sequence_checker(new SequenceCheckerImpl);
+    ASSERT_TRUE(SequencedTaskRunnerHandle::IsSet());
+    scoped_refptr<SequencedTaskRunner> task_runner =
+        SequencedTaskRunnerHandle::Get();
+    ASSERT_TRUE(task_runner);
+    task_runner->PostTask(
+        FROM_HERE, base::Bind(&SequencedTaskRunnerHandleTest::CheckValidThread,
+                              base::Passed(&sequence_checker), callback));
+  }
+
+ private:
+  static void CheckValidThread(scoped_ptr<SequenceCheckerImpl> sequence_checker,
+                               const Closure& callback) {
+    EXPECT_TRUE(sequence_checker->CalledOnValidSequencedThread());
+    callback.Run();
+  }
+
+  MessageLoop message_loop_;
+};
+
+TEST_F(SequencedTaskRunnerHandleTest, FromMessageLoop) {
+  RunLoop run_loop;
+  GetTaskRunner(run_loop.QuitClosure());
+  run_loop.Run();
+}
+
+TEST_F(SequencedTaskRunnerHandleTest, FromSequencedWorkerPool) {
+  // Wrap the SequencedWorkerPool to avoid leaks due to its asynchronous
+  // destruction.
+  SequencedWorkerPoolOwner owner(3, "Test");
+  WaitableEvent event(false, false);
+  owner.pool()->PostSequencedWorkerTask(
+      owner.pool()->GetSequenceToken(), FROM_HERE,
+      base::Bind(&SequencedTaskRunnerHandleTest::GetTaskRunner,
+                 base::Bind(&WaitableEvent::Signal, base::Unretained(&event))));
+  event.Wait();
+  owner.pool()->Shutdown();
+}
+
+class ThreadRunner : public DelegateSimpleThread::Delegate {
+ public:
+  void Run() override {
+    ASSERT_FALSE(SequencedTaskRunnerHandle::IsSet());
+  }
+
+ private:
+  Closure callback_;
+};
+
+TEST_F(SequencedTaskRunnerHandleTest, FromSimpleThread) {
+  ThreadRunner thread_runner;
+  DelegateSimpleThread thread(&thread_runner, "Background thread");
+  thread.Start();
+  thread.Join();
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
index 7bbca92..ed79897 100644
--- a/base/threading/sequenced_worker_pool.cc
+++ b/base/threading/sequenced_worker_pool.cc
@@ -219,10 +219,6 @@
          static_cast<uint64>(reinterpret_cast<intptr_t>(pool));
 }
 
-base::LazyInstance<base::ThreadLocalPointer<
-    SequencedWorkerPool::SequenceToken> >::Leaky g_lazy_tls_ptr =
-        LAZY_INSTANCE_INITIALIZER;
-
 }  // namespace
 
 // Worker ---------------------------------------------------------------------
@@ -239,6 +235,9 @@
   // SimpleThread implementation. This actually runs the background thread.
   void Run() override;
 
+  // Gets the worker for the current thread out of thread-local storage.
+  static Worker* GetForCurrentThread();
+
   // Indicates that a task is about to be run. The parameters provide
   // additional metainformation about the task being run.
   void set_running_task_info(SequenceToken token,
@@ -264,7 +263,14 @@
     return task_shutdown_behavior_;
   }
 
+  scoped_refptr<SequencedWorkerPool> worker_pool() const {
+    return worker_pool_;
+  }
+
  private:
+  static LazyInstance<ThreadLocalPointer<SequencedWorkerPool::Worker>>::Leaky
+      lazy_tls_ptr_;
+
   scoped_refptr<SequencedWorkerPool> worker_pool_;
   // The sequence token of the task being processed. Only valid when
   // is_processing_task_ is true.
@@ -508,9 +514,10 @@
   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_);
+  // Store a pointer to this worker in thread local storage for static function
+  // access.
+  DCHECK(!lazy_tls_ptr_.Get().Get());
+  lazy_tls_ptr_.Get().Set(this);
 
   // Just jump back to the Inner object to run the thread, since it has all the
   // tracking information and queues. It might be more natural to implement
@@ -519,9 +526,23 @@
   // 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;
+  worker_pool_ = nullptr;
 }
 
+// static
+SequencedWorkerPool::Worker*
+SequencedWorkerPool::Worker::GetForCurrentThread() {
+  // Don't construct lazy instance on check.
+  if (lazy_tls_ptr_ == nullptr)
+    return nullptr;
+
+  return lazy_tls_ptr_.Get().Get();
+}
+
+// static
+LazyInstance<ThreadLocalPointer<SequencedWorkerPool::Worker>>::Leaky
+    SequencedWorkerPool::Worker::lazy_tls_ptr_ = LAZY_INSTANCE_INITIALIZER;
+
 // Inner definitions ---------------------------------------------------------
 
 SequencedWorkerPool::Inner::Inner(
@@ -619,9 +640,10 @@
     // 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))));
+    TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+        "SequencedWorkerPool::Inner::PostTask",
+        TRACE_ID_MANGLE(GetTaskTraceID(sequenced, static_cast<void*>(this))),
+        TRACE_EVENT_FLAG_FLOW_OUT);
 
     sequenced.sequence_task_number = LockedGetNextSequenceTaskNumber();
 
@@ -754,12 +776,12 @@
       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());
+        TRACE_EVENT_WITH_FLOW2(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+            "SequencedWorkerPool::Inner::ThreadLoop",
+            TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this))),
+            TRACE_EVENT_FLAG_FLOW_IN,
+            "src_file", task.posted_from.file_name(),
+            "src_func", task.posted_from.function_name());
         int new_thread_id = WillRunWorkerTask(task);
         {
           AutoUnlock unlock(lock_);
@@ -1144,17 +1166,28 @@
 
 // SequencedWorkerPool --------------------------------------------------------
 
+std::string SequencedWorkerPool::SequenceToken::ToString() const {
+  return base::StringPrintf("[%d]", id_);
+}
+
 // static
 SequencedWorkerPool::SequenceToken
 SequencedWorkerPool::GetSequenceTokenForCurrentThread() {
-  // Don't construct lazy instance on check.
-  if (g_lazy_tls_ptr == NULL)
+  Worker* worker = Worker::GetForCurrentThread();
+  if (!worker)
     return SequenceToken();
 
-  SequencedWorkerPool::SequenceToken* token = g_lazy_tls_ptr.Get().Get();
-  if (!token)
-    return SequenceToken();
-  return *token;
+  return worker->task_sequence_token();
+}
+
+// static
+scoped_refptr<SequencedWorkerPool>
+SequencedWorkerPool::GetWorkerPoolForCurrentThread() {
+  Worker* worker = Worker::GetForCurrentThread();
+  if (!worker)
+    return nullptr;
+
+  return worker->worker_pool();
 }
 
 SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h
index ee282bc..9369fb7 100644
--- a/base/threading/sequenced_worker_pool.h
+++ b/base/threading/sequenced_worker_pool.h
@@ -121,7 +121,7 @@
 
   // Opaque identifier that defines sequencing of tasks posted to the worker
   // pool.
-  class SequenceToken {
+  class BASE_EXPORT SequenceToken {
    public:
     SequenceToken() : id_(0) {}
     ~SequenceToken() {}
@@ -135,6 +135,10 @@
       return id_ != 0;
     }
 
+    // Returns a string representation of this token. This method should only be
+    // used for debugging.
+    std::string ToString() const;
+
    private:
     friend class SequencedWorkerPool;
 
@@ -157,17 +161,21 @@
   // an unsequenced task, returns an invalid SequenceToken.
   static SequenceToken GetSequenceTokenForCurrentThread();
 
+  // Returns the SequencedWorkerPool that owns this thread, or null if the
+  // current thread is not a SequencedWorkerPool worker thread.
+  static scoped_refptr<SequencedWorkerPool> GetWorkerPoolForCurrentThread();
+
   // When constructing a SequencedWorkerPool, there must be a
-  // MessageLoop on the current thread unless you plan to deliberately
-  // leak it.
+  // ThreadTaskRunnerHandle on the current thread unless you plan to
+  // deliberately leak it.
 
   // Pass the maximum number of threads (they will be lazily created as needed)
   // and a prefix for the thread name to aid in debugging.
   SequencedWorkerPool(size_t max_threads,
                       const std::string& thread_name_prefix);
 
-  // Like above, but with |observer| for testing.  Does not take
-  // ownership of |observer|.
+  // 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);
diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc
index 05989a5..5812ee7 100644
--- a/base/threading/sequenced_worker_pool_unittest.cc
+++ b/base/threading/sequenced_worker_pool_unittest.cc
@@ -904,6 +904,49 @@
   pool()->FlushForTesting();
 }
 
+namespace {
+
+void CheckWorkerPoolAndSequenceToken(
+    const scoped_refptr<SequencedWorkerPool>& expected_pool,
+    SequencedWorkerPool::SequenceToken expected_token) {
+  SequencedWorkerPool::SequenceToken token =
+      SequencedWorkerPool::GetSequenceTokenForCurrentThread();
+  EXPECT_EQ(expected_token.ToString(), token.ToString());
+
+  scoped_refptr<SequencedWorkerPool> pool =
+      SequencedWorkerPool::GetWorkerPoolForCurrentThread();
+  EXPECT_EQ(expected_pool, pool);
+}
+
+}  // namespace
+
+TEST_F(SequencedWorkerPoolTest, GetWorkerPoolAndSequenceTokenForCurrentThread) {
+  EnsureAllWorkersCreated();
+
+  // The current thread should have neither a worker pool nor a sequence token.
+  SequencedWorkerPool::SequenceToken local_token =
+      SequencedWorkerPool::GetSequenceTokenForCurrentThread();
+  scoped_refptr<SequencedWorkerPool> local_pool =
+      SequencedWorkerPool::GetWorkerPoolForCurrentThread();
+  EXPECT_FALSE(local_token.IsValid()) << local_token.ToString();
+  EXPECT_FALSE(local_pool);
+
+  SequencedWorkerPool::SequenceToken token1 = pool()->GetSequenceToken();
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&CheckWorkerPoolAndSequenceToken, pool(), token1));
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&CheckWorkerPoolAndSequenceToken, pool(), token2));
+
+  pool()->PostWorkerTask(FROM_HERE,
+                         base::Bind(&CheckWorkerPoolAndSequenceToken, pool(),
+                                    SequencedWorkerPool::SequenceToken()));
+
+  pool()->FlushForTesting();
+}
+
 TEST(SequencedWorkerPoolRefPtrTest, ShutsDownCleanWithContinueOnShutdown) {
   MessageLoop loop;
   scoped_refptr<SequencedWorkerPool> pool(new SequencedWorkerPool(3, "Pool"));
@@ -948,6 +991,8 @@
 INSTANTIATE_TYPED_TEST_CASE_P(
     SequencedWorkerPool, TaskRunnerTest,
     SequencedWorkerPoolTaskRunnerTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(SequencedWorkerPool, TaskRunnerAffinityTest,
+                              SequencedWorkerPoolTaskRunnerTestDelegate);
 
 class SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate {
  public:
@@ -985,6 +1030,9 @@
 INSTANTIATE_TYPED_TEST_CASE_P(
     SequencedWorkerPoolTaskRunner, TaskRunnerTest,
     SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolTaskRunner, TaskRunnerAffinityTest,
+    SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate);
 
 class SequencedWorkerPoolSequencedTaskRunnerTestDelegate {
  public:
@@ -1022,10 +1070,17 @@
 INSTANTIATE_TYPED_TEST_CASE_P(
     SequencedWorkerPoolSequencedTaskRunner, TaskRunnerTest,
     SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolSequencedTaskRunner, TaskRunnerAffinityTest,
+    SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
 
 INSTANTIATE_TYPED_TEST_CASE_P(
     SequencedWorkerPoolSequencedTaskRunner, SequencedTaskRunnerTest,
     SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolSequencedTaskRunner,
+    SequencedTaskRunnerDelayedTest,
+    SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
 
 }  // namespace
 
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
index 1bc3113..7059cea 100644
--- a/base/threading/simple_thread.cc
+++ b/base/threading/simple_thread.cc
@@ -29,7 +29,13 @@
 
 void SimpleThread::Start() {
   DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
-  bool success = PlatformThread::Create(options_.stack_size(), this, &thread_);
+  bool success;
+  if (options_.priority() == ThreadPriority::NORMAL) {
+    success = PlatformThread::Create(options_.stack_size(), this, &thread_);
+  } else {
+    success = PlatformThread::CreateWithPriority(options_.stack_size(), this,
+                                                 &thread_, options_.priority());
+  }
   DCHECK(success);
   base::ThreadRestrictions::ScopedAllowWait allow_wait;
   event_.Wait();  // Wait for the thread to complete initialization.
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
index ecd3604..2f0eb4d 100644
--- a/base/threading/simple_thread.h
+++ b/base/threading/simple_thread.h
@@ -59,16 +59,23 @@
  public:
   class BASE_EXPORT Options {
    public:
-    Options() : stack_size_(0) { }
-    ~Options() { }
+    Options() : stack_size_(0), priority_(ThreadPriority::NORMAL) {}
+    explicit Options(ThreadPriority priority)
+        : stack_size_(0), priority_(priority) {}
+    ~Options() {}
 
     // We use the standard compiler-supplied copy constructor.
 
     // A custom stack size, or 0 for the system default.
     void set_stack_size(size_t size) { stack_size_ = size; }
     size_t stack_size() const { return stack_size_; }
+
+    // A custom thread priority.
+    void set_priority(ThreadPriority priority) { priority_ = priority; }
+    ThreadPriority priority() const { return priority_; }
    private:
     size_t stack_size_;
+    ThreadPriority priority_;
   };
 
   // Create a SimpleThread.  |options| should be used to manage any specific
@@ -104,12 +111,6 @@
   // 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_;
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index 0e4aab2..9d1ca8e 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -7,7 +7,6 @@
 #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"
@@ -37,31 +36,19 @@
   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) {
+      stack_size(0),
+      priority(ThreadPriority::NORMAL) {
 }
 
 Thread::Options::Options(MessageLoop::Type type,
                          size_t size)
     : message_loop_type(type),
       timer_slack(TIMER_SLACK_NONE),
-      stack_size(size) {
+      stack_size(size),
+      priority(ThreadPriority::NORMAL) {
 }
 
 Thread::Options::~Options() {
@@ -72,14 +59,15 @@
 #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) {
+      id_(kInvalidThreadId),
+      id_event_(true, false),
+      message_loop_(nullptr),
+      message_loop_timer_slack_(TIMER_SLACK_NONE),
+      name_(name),
+      start_event_(false, false) {
 }
 
 Thread::~Thread() {
@@ -102,36 +90,61 @@
       (options.message_loop_type == MessageLoop::TYPE_UI));
 #endif
 
+  // Reset |id_| here to support restarting the thread.
+  id_event_.Reset();
+  id_ = kInvalidThreadId;
+
   SetThreadWasQuitProperly(false);
 
-  StartupData startup_data(options);
-  startup_data_ = &startup_data;
+  MessageLoop::Type type = options.message_loop_type;
+  if (!options.message_pump_factory.is_null())
+    type = MessageLoop::TYPE_CUSTOM;
 
-  if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
-    DLOG(ERROR) << "failed to create thread";
-    startup_data_ = NULL;
-    return false;
+  message_loop_timer_slack_ = options.timer_slack;
+  scoped_ptr<MessageLoop> message_loop = MessageLoop::CreateUnbound(
+      type, options.message_pump_factory);
+  message_loop_ = message_loop.get();
+  start_event_.Reset();
+
+  // Hold the thread_lock_ while starting a new thread, so that we can make sure
+  // that thread_ is populated before the newly created thread accesses it.
+  {
+    AutoLock lock(thread_lock_);
+    if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_,
+                                            options.priority)) {
+      DLOG(ERROR) << "failed to create thread";
+      message_loop_ = nullptr;
+      return false;
+    }
   }
 
-  // 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;
+  // The ownership of message_loop is managemed by the newly created thread
+  // within the ThreadMain.
+  ignore_result(message_loop.release());
 
   DCHECK(message_loop_);
   return true;
 }
 
+bool Thread::StartAndWaitForTesting() {
+  bool result = Start();
+  if (!result)
+    return false;
+  WaitUntilThreadStarted();
+  return true;
+}
+
+bool Thread::WaitUntilThreadStarted() const {
+  if (!message_loop_)
+    return false;
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  start_event_.Wait();
+  return true;
+}
+
 void Thread::Stop() {
-  if (!started_)
+  AutoLock lock(thread_lock_);
+  if (thread_.is_null())
     return;
 
   StopSoon();
@@ -142,22 +155,18 @@
   // the thread exits.  Some consumers are abusing the API.  Make them stop.
   //
   PlatformThread::Join(thread_);
+  thread_ = base::PlatformThreadHandle();
 
-  // The thread should NULL message_loop_ on exit.
+  // The thread should nullify 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());
+  DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
 
   if (stopping_ || !message_loop_)
     return;
@@ -166,15 +175,24 @@
   task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
 }
 
-bool Thread::IsRunning() const {
-  return running_;
+PlatformThreadId Thread::GetThreadId() const {
+  // If the thread is created but not started yet, wait for |id_| being ready.
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  id_event_.Wait();
+  return id_;
 }
 
-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);
+bool Thread::IsRunning() const {
+  // If the thread's already started (i.e. message_loop_ is non-null) and
+  // not yet requested to stop (i.e. stopping_ is false) we can just return
+  // true. (Note that stopping_ is touched only on the same thread that
+  // starts / started the new thread so we need no locking here.)
+  if (message_loop_ && !stopping_)
+    return true;
+  // Otherwise check the running_ flag, which is set to true by the new thread
+  // only while it is inside Run().
+  AutoLock lock(running_lock_);
+  return running_;
 }
 
 void Thread::Run(MessageLoop* message_loop) {
@@ -194,60 +212,66 @@
 }
 
 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));
-    }
+  // First, make GetThreadId() available to avoid deadlocks. It could be called
+  // any place in the following thread initialization code.
+  id_ = PlatformThread::CurrentId();
+  DCHECK_NE(kInvalidThreadId, id_);
+  id_event_.Signal();
 
-    // Complete the initialization of our Thread object.
-    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();
+  // Complete the initialization of our Thread object.
+  PlatformThread::SetName(name_.c_str());
+  ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.
+
+  // Lazily initialize the message_loop so that it can run on this thread.
+  DCHECK(message_loop_);
+  scoped_ptr<MessageLoop> message_loop(message_loop_);
+  message_loop_->BindToCurrentThread();
+  message_loop_->set_thread_name(name_);
+  message_loop_->SetTimerSlack(message_loop_timer_slack_);
 
 #if defined(OS_WIN)
-    scoped_ptr<win::ScopedCOMInitializer> com_initializer;
-    if (com_status_ != NONE) {
-      com_initializer.reset((com_status_ == STA) ?
-          new win::ScopedCOMInitializer() :
-          new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
-    }
-#endif
-
-    // 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;
+  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.
+  Init();
+
+  {
+    AutoLock lock(running_lock_);
+    running_ = true;
+  }
+
+  start_event_.Signal();
+
+  Run(message_loop_);
+
+  {
+    AutoLock lock(running_lock_);
+    running_ = false;
+  }
+
+  // Let the thread do extra cleanup.
+  CleanUp();
+
+#if defined(OS_WIN)
+  com_initializer.reset();
+#endif
+
+  if (message_loop->type() != MessageLoop::TYPE_CUSTOM) {
+    // Assert that MessageLoop::QuitWhenIdle was called by ThreadQuitHelper.
+    // Don't check for custom message pumps, because their shutdown might not
+    // allow this.
+    DCHECK(GetThreadWasQuitProperly());
+  }
+
+  // We can't receive messages anymore.
+  // (The message loop is destructed at the end of this block)
+  message_loop_ = nullptr;
 }
 
 }  // namespace base
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 4915606..c8a1c80 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -13,6 +13,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/timer_slack.h"
 #include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
 
 namespace base {
@@ -45,7 +47,7 @@
     // This is ignored if message_pump_factory.is_null() is false.
     MessageLoop::Type message_loop_type;
 
-    // Specify timer slack for thread message loop.
+    // Specifies timer slack for thread message loop.
     TimerSlack timer_slack;
 
     // Used to create the MessagePump for the MessageLoop. The callback is Run()
@@ -58,6 +60,9 @@
     // This does not necessarily correspond to the thread's initial stack size.
     // A value of 0 indicates that the default maximum should be used.
     size_t stack_size;
+
+    // Specifies the initial thread priority.
+    ThreadPriority priority;
   };
 
   // Constructor.
@@ -81,7 +86,7 @@
   // 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_);
+    DCHECK(!message_loop_);
     com_status_ = use_mta ? MTA : STA;
   }
 #endif
@@ -103,6 +108,18 @@
   // callback.
   bool StartWithOptions(const Options& options);
 
+  // Starts the thread and wait for the thread to start and run initialization
+  // before returning. It's same as calling Start() and then
+  // WaitUntilThreadStarted().
+  // Note that using this (instead of Start() or StartWithOptions() causes
+  // jank on the calling thread, should be used only in testing code.
+  bool StartAndWaitForTesting();
+
+  // Blocks until the thread starts running. Called within StartAndWait().
+  // Note that calling this causes jank on the calling thread, must be used
+  // carefully for production code.
+  bool WaitUntilThreadStarted() const;
+
   // Signals the thread to exit and returns once the thread has exited.  After
   // this method returns, the Thread object is completely reset and may be used
   // as if it were newly constructed (i.e., Start may be called again).
@@ -131,32 +148,20 @@
   // 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.
+  // this will return nullptr.
   //
   // NOTE: You must not call this MessageLoop's Quit method directly.  Use
   // the Thread's Stop method instead.
   //
   MessageLoop* message_loop() const { return message_loop_; }
 
-  // Returns a 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
+  // methods to execute code on the thread. Returns nullptr if the thread is not
   // running (e.g. before Start or after Stop have been called). Callers can
   // hold on to this even after the thread is gone; in this situation, attempts
   // to PostTask() will fail.
   scoped_refptr<SingleThreadTaskRunner> task_runner() const {
-    return message_loop_->task_runner();
+    return message_loop_ ? message_loop_->task_runner() : nullptr;
   }
 
   // Returns the name of this thread (for display in debugger too).
@@ -165,15 +170,17 @@
   // The native thread handle.
   PlatformThreadHandle thread_handle() { return thread_; }
 
-  // The thread ID.
-  PlatformThreadId thread_id() const { return thread_id_; }
+  // Returns the thread ID.  Should not be called before the first Start*()
+  // call.  Keeps on returning the same ID even after a Stop() call. The next
+  // Start*() call renews the ID.
+  //
+  // WARNING: This function will block if the thread hasn't started yet.
+  //
+  PlatformThreadId GetThreadId() const;
 
   // Returns true if the thread has been started, and not yet stopped.
   bool IsRunning() const;
 
-  // 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() {}
@@ -208,33 +215,38 @@
   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.
+  // |message_loop_|. It may non-nullptr and invalid.
+  // Should be written on the thread that created this thread. Also read data
+  // could be wrong on other threads.
   bool stopping_;
 
   // True while inside of Run().
   bool running_;
-
-  // Used to pass data to ThreadMain.
-  struct StartupData;
-  StartupData* startup_data_;
+  mutable base::Lock running_lock_;  // Protects |running_|.
 
   // The thread's handle.
   PlatformThreadHandle thread_;
+  mutable base::Lock thread_lock_;  // Protects |thread_|.
+
+  // The thread's id once it has started.
+  PlatformThreadId id_;
+  mutable WaitableEvent id_event_;  // Protects |id_|.
 
   // The thread's message loop.  Valid only while the thread is alive.  Set
   // by the created thread.
   MessageLoop* message_loop_;
 
-  // Our thread's ID.
-  PlatformThreadId thread_id_;
+  // Stores Options::timer_slack_ until the message loop has been bound to
+  // a thread.
+  TimerSlack message_loop_timer_slack_;
 
   // The name of the thread.  Used for debugging purposes.
   std::string name_;
 
+  // Signaled when the created thread gets ready to use the message loop.
+  mutable WaitableEvent start_event_;
+
   friend void ThreadQuitHelper();
 
   DISALLOW_COPY_AND_ASSIGN(Thread);
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
index 449247a..1d970f0 100644
--- a/base/threading/thread_checker.h
+++ b/base/threading/thread_checker.h
@@ -5,23 +5,19 @@
 #ifndef BASE_THREADING_THREAD_CHECKER_H_
 #define BASE_THREADING_THREAD_CHECKER_H_
 
+#include "base/logging.h"
+#include "base/threading/thread_checker_impl.h"
+
 // Apart from debug builds, we also enable the thread checker in
 // builds with DCHECK_ALWAYS_ON so that trybots and waterfall bots
 // with this define will get the same level of thread checking as
 // debug bots.
-//
-// 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))
+#if DCHECK_IS_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.
diff --git a/base/threading/thread_id_name_manager.h b/base/threading/thread_id_name_manager.h
index 927d25f..1ba7e13 100644
--- a/base/threading/thread_id_name_manager.h
+++ b/base/threading/thread_id_name_manager.h
@@ -13,10 +13,11 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
 
-template <typename T> struct DefaultSingletonTraits;
-
 namespace base {
 
+template <typename T>
+struct DefaultSingletonTraits;
+
 class BASE_EXPORT ThreadIdNameManager {
  public:
   static ThreadIdNameManager* GetInstance();
diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc
index b5953d5..350dc0f 100644
--- a/base/threading/thread_id_name_manager_unittest.cc
+++ b/base/threading/thread_id_name_manager_unittest.cc
@@ -21,11 +21,11 @@
   base::Thread thread_a(kAThread);
   base::Thread thread_b(kBThread);
 
-  thread_a.Start();
-  thread_b.Start();
+  thread_a.StartAndWaitForTesting();
+  thread_b.StartAndWaitForTesting();
 
-  EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
-  EXPECT_STREQ(kBThread, manager->GetName(thread_b.thread_id()));
+  EXPECT_STREQ(kAThread, manager->GetName(thread_a.GetThreadId()));
+  EXPECT_STREQ(kBThread, manager->GetName(thread_b.GetThreadId()));
 
   thread_b.Stop();
   thread_a.Stop();
@@ -35,30 +35,30 @@
   base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
   base::Thread thread_a(kAThread);
 
-  thread_a.Start();
+  thread_a.StartAndWaitForTesting();
   {
     base::Thread thread_b(kBThread);
-    thread_b.Start();
+    thread_b.StartAndWaitForTesting();
     thread_b.Stop();
   }
-  EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+  EXPECT_STREQ(kAThread, manager->GetName(thread_a.GetThreadId()));
 
   thread_a.Stop();
-  EXPECT_STREQ("", manager->GetName(thread_a.thread_id()));
+  EXPECT_STREQ("", manager->GetName(thread_a.GetThreadId()));
 }
 
 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();
+  thread_a.StartAndWaitForTesting();
+  base::PlatformThreadId a_id = thread_a.GetThreadId();
   EXPECT_STREQ(kAThread, manager->GetName(a_id));
   thread_a.Stop();
 
-  thread_a.Start();
+  thread_a.StartAndWaitForTesting();
   EXPECT_STREQ("", manager->GetName(a_id));
-  EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+  EXPECT_STREQ(kAThread, manager->GetName(thread_a.GetThreadId()));
   thread_a.Stop();
 }
 
diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc
index 0bb396c..701f6a2 100644
--- a/base/threading/thread_local_storage.cc
+++ b/base/threading/thread_local_storage.cc
@@ -192,8 +192,8 @@
 }  // namespace internal
 
 ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) {
-  initialized_ = false;
   slot_ = 0;
+  base::subtle::Release_Store(&initialized_, 0);
   Initialize(destructor);
 }
 
@@ -211,7 +211,7 @@
 
   // Setup our destructor.
   g_tls_destructors[slot_] = destructor;
-  initialized_ = true;
+  base::subtle::Release_Store(&initialized_, 1);
 }
 
 void ThreadLocalStorage::StaticSlot::Free() {
@@ -221,7 +221,7 @@
   DCHECK_LT(slot_, kThreadLocalStorageSize);
   g_tls_destructors[slot_] = NULL;
   slot_ = 0;
-  initialized_ = false;
+  base::subtle::Release_Store(&initialized_, 0);
 }
 
 void* ThreadLocalStorage::StaticSlot::Get() const {
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
index 50f8868..195bff6 100644
--- a/base/threading/thread_local_storage.h
+++ b/base/threading/thread_local_storage.h
@@ -5,6 +5,7 @@
 #ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_
 #define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
 
+#include "base/atomicops.h"
 #include "base/base_export.h"
 #include "base/basictypes.h"
 
@@ -114,10 +115,12 @@
     // value 'value'.
     void Set(void* value);
 
-    bool initialized() const { return initialized_; }
+    bool initialized() const {
+      return base::subtle::Acquire_Load(&initialized_) != 0;
+    }
 
     // The internals of this struct should be considered private.
-    bool initialized_;
+    base::subtle::Atomic32 initialized_;
     int slot_;
   };
 
diff --git a/base/threading/thread_perftest.cc b/base/threading/thread_perftest.cc
index 3bc9fb4..d6fbc3e 100644
--- a/base/threading/thread_perftest.cc
+++ b/base/threading/thread_perftest.cc
@@ -44,18 +44,21 @@
   // 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 Init() {
+    if (ThreadTicks::IsSupported())
+      ThreadTicks::WaitUntilInitialized();
+  }
   virtual void PingPong(int hops) = 0;
   virtual void Reset() {}
 
-  void TimeOnThread(base::TimeTicks* ticks, base::WaitableEvent* done) {
-    *ticks = base::TimeTicks::ThreadNow();
+  void TimeOnThread(base::ThreadTicks* ticks, base::WaitableEvent* done) {
+    *ticks = base::ThreadTicks::Now();
     done->Signal();
   }
 
-  base::TimeTicks ThreadNow(base::Thread* thread) {
+  base::ThreadTicks ThreadNow(base::Thread* thread) {
     base::WaitableEvent done(false, false);
-    base::TimeTicks ticks;
+    base::ThreadTicks ticks;
     thread->task_runner()->PostTask(
         FROM_HERE, base::Bind(&ThreadPerfTest::TimeOnThread,
                               base::Unretained(this), &ticks, &done));
@@ -65,11 +68,11 @@
 
   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;
+    std::vector<base::ThreadTicks> thread_starts;
     while (threads_.size() < num_threads) {
       threads_.push_back(new base::Thread("PingPonger"));
       threads_.back()->Start();
-      if (base::TimeTicks::IsThreadNowSupported())
+      if (base::ThreadTicks::IsSupported())
         thread_starts.push_back(ThreadNow(threads_.back()));
     }
 
@@ -84,7 +87,7 @@
     // but that should be in the noise given enough runs.
     base::TimeDelta thread_time;
     while (threads_.size()) {
-      if (base::TimeTicks::IsThreadNowSupported()) {
+      if (base::ThreadTicks::IsSupported()) {
         thread_time += ThreadNow(threads_.back()) - thread_starts.back();
         thread_starts.pop_back();
       }
@@ -102,7 +105,7 @@
         "task", "", name + "_time ", us_per_task_clock, "us/hop", true);
 
     // Total utilization across threads if available (likely higher).
-    if (base::TimeTicks::IsThreadNowSupported()) {
+    if (base::ThreadTicks::IsSupported()) {
       perf_test::PrintResult(
           "task", "", name + "_cpu ", us_per_task_cpu, "us/hop", true);
     }
diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc
index 871f2dc..00306c5 100644
--- a/base/threading/thread_restrictions.cc
+++ b/base/threading/thread_restrictions.cc
@@ -23,7 +23,7 @@
 LazyInstance<ThreadLocalBoolean>::Leaky
     g_wait_disallowed = LAZY_INSTANCE_INITIALIZER;
 
-}  // anonymous namespace
+}  // namespace
 
 // static
 bool ThreadRestrictions::SetIOAllowed(bool allowed) {
@@ -69,7 +69,7 @@
 // static
 void ThreadRestrictions::AssertWaitAllowed() {
   if (g_wait_disallowed.Get().Get()) {
-    LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent"
+    LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent "
                << "jank and deadlock.";
   }
 }
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 54f50eb..66b8e8d 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -22,7 +22,7 @@
 
 namespace cc {
 class CompletionEvent;
-class TaskGraphRunner;
+class SingleThreadTaskGraphRunner;
 }
 namespace chromeos {
 class BlockingMethodCaller;
@@ -40,10 +40,11 @@
 class BrowserTestBase;
 class GpuChannelHost;
 class NestedMessagePumpAndroid;
-class RenderWidgetResizeHelper;
 class ScopedAllowWaitForAndroidLayoutTests;
 class ScopedAllowWaitForDebugURL;
+class SoftwareOutputDeviceMus;
 class TextInputClientMac;
+class RasterWorkerPool;
 }  // namespace content
 namespace dbus {
 class Bus;
@@ -52,12 +53,11 @@
 class BackendImpl;
 class InFlightIO;
 }
-namespace mojo {
-namespace common {
-class WatcherThreadManager;
-}
+namespace gles2 {
+class CommandBufferClientImpl;
 }
 namespace net {
+class NetworkChangeNotifierMac;
 namespace internal {
 class AddressTrackerLinux;
 }
@@ -67,6 +67,14 @@
 class AutoThread;
 }
 
+namespace ui {
+class WindowResizeHelperMac;
+}
+
+namespace views {
+class WindowManagerConnection;
+}
+
 namespace base {
 
 namespace android {
@@ -174,15 +182,15 @@
   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 cc::SingleThreadTaskGraphRunner;
+  friend class content::RasterWorkerPool;
   friend class remoting::AutoThread;
+  friend class ui::WindowResizeHelperMac;
   friend class MessagePumpDefault;
   friend class SequencedWorkerPool;
   friend class SimpleThread;
@@ -190,6 +198,7 @@
   friend class ThreadTestHelper;
   friend class PlatformThread;
   friend class android::JavaHandlerThread;
+  friend class gles2::CommandBufferClientImpl;
 
   // END ALLOWED USAGE.
   // BEGIN USAGE THAT NEEDS TO BE FIXED.
@@ -206,9 +215,14 @@
   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 net::NetworkChangeNotifierMac;     // 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 !defined(OFFICIAL_BUILD)
+  friend class content::SoftwareOutputDeviceMus;  // Interim non-production code
+#endif
+  friend class views::WindowManagerConnection;
+// END USAGE THAT NEEDS TO BE FIXED.
 
 #if ENABLE_THREAD_RESTRICTIONS
   static bool SetWaitAllowed(bool allowed);
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index a89768e..9422081 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -105,6 +106,15 @@
   base::MessageLoop::current()->AddDestructionObserver(observer);
 }
 
+// Task that calls GetThreadId() of |thread|, stores the result into |id|, then
+// signal |event|.
+void ReturnThreadId(base::Thread* thread,
+                    base::PlatformThreadId* id,
+                    base::WaitableEvent* event) {
+  *id = thread->GetThreadId();
+  event->Signal();
+}
+
 }  // namespace
 
 TEST_F(ThreadTest, Restart) {
@@ -194,11 +204,53 @@
   EXPECT_EQ("ThreadName", a.thread_name());
 }
 
-// Make sure we can't use a thread between Start() and Init().
+TEST_F(ThreadTest, ThreadId) {
+  Thread a("ThreadId0");
+  Thread b("ThreadId1");
+  a.Start();
+  b.Start();
+
+  // Post a task that calls GetThreadId() on the created thread.
+  base::WaitableEvent event(false, false);
+  base::PlatformThreadId id_from_new_thread;
+  a.task_runner()->PostTask(
+      FROM_HERE, base::Bind(ReturnThreadId, &a, &id_from_new_thread, &event));
+
+  // Call GetThreadId() on the current thread before calling event.Wait() so
+  // that this test can find a race issue with TSAN.
+  base::PlatformThreadId id_from_current_thread = a.GetThreadId();
+
+  // Check if GetThreadId() returns consistent value in both threads.
+  event.Wait();
+  EXPECT_EQ(id_from_current_thread, id_from_new_thread);
+
+  // A started thread should have a valid ID.
+  EXPECT_NE(base::kInvalidThreadId, a.GetThreadId());
+  EXPECT_NE(base::kInvalidThreadId, b.GetThreadId());
+
+  // Each thread should have a different thread ID.
+  EXPECT_NE(a.GetThreadId(), b.GetThreadId());
+}
+
+TEST_F(ThreadTest, ThreadIdWithRestart) {
+  Thread a("ThreadIdWithRestart");
+  base::PlatformThreadId previous_id = base::kInvalidThreadId;
+
+  for (size_t i = 0; i < 16; ++i) {
+    EXPECT_TRUE(a.Start());
+    base::PlatformThreadId current_id = a.GetThreadId();
+    EXPECT_NE(previous_id, current_id);
+    previous_id = current_id;
+    a.Stop();
+  }
+}
+
+// Make sure Init() is called after Start() and before
+// WaitUntilThreadInitialized() returns.
 TEST_F(ThreadTest, SleepInsideInit) {
   SleepInsideInitThread t;
   EXPECT_FALSE(t.InitCalled());
-  t.Start();
+  t.StartAndWaitForTesting();
   EXPECT_TRUE(t.InitCalled());
 }
 
@@ -233,3 +285,8 @@
   EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
   EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
 }
+
+TEST_F(ThreadTest, ThreadNotStarted) {
+  Thread a("Inert");
+  EXPECT_EQ(nullptr, a.task_runner());
+}
diff --git a/base/threading/worker_pool.cc b/base/threading/worker_pool.cc
index bc016ce..71b1a2b 100644
--- a/base/threading/worker_pool.cc
+++ b/base/threading/worker_pool.cc
@@ -21,6 +21,7 @@
   explicit PostTaskAndReplyWorkerPool(bool task_is_slow)
       : task_is_slow_(task_is_slow) {
   }
+  ~PostTaskAndReplyWorkerPool() override = default;
 
  private:
   bool PostTask(const tracked_objects::Location& from_here,
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc
index 349b5d7..ea9ece4 100644
--- a/base/threading/worker_pool_posix.cc
+++ b/base/threading/worker_pool_posix.cc
@@ -33,7 +33,8 @@
   ~WorkerPoolImpl();
 
   void PostTask(const tracked_objects::Location& from_here,
-                const base::Closure& task, bool task_is_slow);
+                const base::Closure& task,
+                bool task_is_slow);
 
  private:
   scoped_refptr<base::PosixDynamicThreadPool> pool_;
@@ -41,15 +42,15 @@
 
 WorkerPoolImpl::WorkerPoolImpl()
     : pool_(new base::PosixDynamicThreadPool("WorkerPool",
-                                             kIdleSecondsBeforeExit)) {
-}
+                                             kIdleSecondsBeforeExit)) {}
 
 WorkerPoolImpl::~WorkerPoolImpl() {
   pool_->Terminate();
 }
 
 void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
-                              const base::Closure& task, bool task_is_slow) {
+                              const base::Closure& task,
+                              bool task_is_slow) {
   pool_->PostTask(from_here, task);
 }
 
@@ -60,8 +61,7 @@
  public:
   WorkerThread(const std::string& name_prefix,
                base::PosixDynamicThreadPool* pool)
-      : name_prefix_(name_prefix),
-        pool_(pool) {}
+      : name_prefix_(name_prefix), pool_(pool) {}
 
   void ThreadMain() override;
 
@@ -74,8 +74,8 @@
 
 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());
+  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);
 
@@ -104,7 +104,8 @@
 
 // static
 bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
-                          const base::Closure& task, bool task_is_slow) {
+                          const base::Closure& task,
+                          bool task_is_slow) {
   g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
   return true;
 }
@@ -145,8 +146,8 @@
 
 void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
   AutoLock locked(lock_);
-  DCHECK(!terminated_) <<
-      "This thread pool is already terminated.  Do not post new tasks.";
+  DCHECK(!terminated_)
+      << "This thread pool is already terminated.  Do not post new tasks.";
 
   pending_tasks_.push(*pending_task);
   pending_task->task.Reset();
@@ -157,8 +158,7 @@
   } else {
     // The new PlatformThread will take ownership of the WorkerThread object,
     // which will delete itself on exit.
-    WorkerThread* worker =
-        new WorkerThread(name_prefix_, this);
+    WorkerThread* worker = new WorkerThread(name_prefix_, this);
     PlatformThread::CreateNonJoinable(0, worker);
   }
 }
diff --git a/base/threading/worker_pool_posix_unittest.cc b/base/threading/worker_pool_posix_unittest.cc
index 354a99c..364f07d 100644
--- a/base/threading/worker_pool_posix_unittest.cc
+++ b/base/threading/worker_pool_posix_unittest.cc
@@ -10,8 +10,8 @@
 #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 "base/threading/platform_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -90,7 +90,7 @@
 class PosixDynamicThreadPoolTest : public testing::Test {
  protected:
   PosixDynamicThreadPoolTest()
-      : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60*60)),
+      : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60 * 60)),
         peer_(pool_.get()),
         counter_(0),
         num_waiting_to_start_(0),
@@ -103,7 +103,8 @@
 
   void TearDown() override {
     // Wake up the idle threads so they can terminate.
-    if (pool_.get()) pool_->Terminate();
+    if (pool_.get())
+      pool_->Terminate();
   }
 
   void WaitForTasksToStart(int num_tasks) {
diff --git a/base/time/time.cc b/base/time/time.cc
index 9834188..53851fb 100644
--- a/base/time/time.cc
+++ b/base/time/time.cc
@@ -144,7 +144,7 @@
     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);
+  return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt);
 }
 
 time_t Time::ToTimeT() const {
@@ -166,11 +166,7 @@
 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));
+  return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt);
 }
 
 double Time::ToDoubleT() const {
@@ -197,10 +193,8 @@
 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);
+  return Time(kTimeTToMicrosecondsOffset) +
+         TimeDelta::FromMillisecondsD(ms_since_epoch);
 }
 
 double Time::ToJsTime() const {
@@ -327,6 +321,11 @@
   return os << as_time_delta.InMicroseconds() << " bogo-microseconds";
 }
 
+std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
+  const TimeDelta as_time_delta = thread_ticks - ThreadTicks();
+  return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
+}
+
 // Time::Exploded -------------------------------------------------------------
 
 inline bool is_in_range(int value, int lo, int hi) {
diff --git a/base/time/time.h b/base/time/time.h
index 0a26778..6c06fbc 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -4,25 +4,47 @@
 
 // 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.
+// (1601-01-01 00:00:00 UTC). System-dependent clock interface routines are
+// defined in time_PLATFORM.cc. Note that values for Time may skew and jump
+// around as the operating system makes adjustments to synchronize (e.g., with
+// NTP servers). Thus, client code that uses the Time class must account for
+// this.
 //
 // TimeDelta represents a duration of time, internally represented in
 // microseconds.
 //
-// TimeTicks 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.
+// TimeTicks and ThreadTicks represent an abstract time that is most of the time
+// incrementing, for use in measuring time durations. Internally, they are
+// represented in microseconds. They can not be converted to a human-readable
+// time, but are guaranteed not to decrease (unlike the Time class). Note that
+// TimeTicks may "stand still" (e.g., if the computer is suspended), and
+// ThreadTicks will "stand still" whenever the thread has been de-scheduled by
+// the operating system.
 //
-// These classes are represented as only a 64-bit value, so they can be
-// efficiently passed by value.
+// All time classes are copyable, assignable, and occupy 64-bits per
+// instance. Thus, they can be efficiently passed by-value (as opposed to
+// by-reference).
 //
 // Definitions of operator<< are provided to make these types work with
 // DCHECK_EQ() and other log macros. For human-readable formatting, see
 // "base/i18n/time_formatting.h".
+//
+// So many choices!  Which time class should you use?  Examples:
+//
+//   Time:        Interpreting the wall-clock time provided by a remote
+//                system. Detecting whether cached resources have
+//                expired. Providing the user with a display of the current date
+//                and time. Determining the amount of time between events across
+//                re-boots of the machine.
+//
+//   TimeTicks:   Tracking the amount of time a task runs. Executing delayed
+//                tasks at the right time. Computing presentation timestamps.
+//                Synchronizing audio and video using TimeTicks as a common
+//                reference clock (lip-sync). Measuring network round-trip
+//                latency.
+//
+//   ThreadTicks: Benchmarking how long the current thread has been doing actual
+//                work.
 
 #ifndef BASE_TIME_TIME_H_
 #define BASE_TIME_TIME_H_
@@ -51,6 +73,8 @@
 // For FILETIME in FromFileTime, until it moves to a new converter class.
 // See TODO(iyengar) below.
 #include <windows.h>
+
+#include "base/gtest_prod_util.h"
 #endif
 
 #include <limits>
@@ -236,6 +260,9 @@
   explicit TimeDelta(int64 delta_us) : delta_(delta_us) {
   }
 
+  // Private method to build a delta from a double.
+  static TimeDelta FromDouble(double value);
+
   // Delta in microseconds.
   int64 delta_;
 };
@@ -388,7 +415,7 @@
   // 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;
+  enum : int64 { kQPCOverflowThreshold = 0x8637BD05AF7 };
 #endif
 
   // Represents an exploded time that can be formatted nicely. This is kind of
@@ -569,7 +596,6 @@
 
 // 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);
@@ -577,7 +603,6 @@
 
 // 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);
@@ -585,7 +610,6 @@
 
 // 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);
@@ -593,44 +617,40 @@
 
 // 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);
+  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);
+  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));
+  return FromDouble(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));
+  return FromDouble(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);
 }
 
+// static
+inline TimeDelta TimeDelta::FromDouble(double value) {
+  double max_magnitude = std::numeric_limits<int64>::max();
+  TimeDelta delta = TimeDelta(static_cast<int64>(value));
+  if (value > max_magnitude)
+    delta = Max();
+  else if (value < -max_magnitude)
+    delta = -Max();
+  return delta;
+}
+
 // For logging use only.
 BASE_EXPORT std::ostream& operator<<(std::ostream& os, Time time);
 
@@ -639,14 +659,6 @@
 // Represents monotonically non-decreasing clock time.
 class BASE_EXPORT TimeTicks : public time_internal::TimeBase<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() : TimeBase(0) {
   }
 
@@ -662,43 +674,6 @@
   // 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
@@ -706,12 +681,14 @@
   static TimeTicks FromQPCValue(LONGLONG qpc_value);
 #endif
 
-  // Get the TimeTick value at the time of the UnixEpoch. This is useful when
-  // you need to relate the value of TimeTicks to a real time and date.
-  // Note: Upon first invocation, this function takes a snapshot of the realtime
-  // clock to establish a reference point.  This function will return the same
-  // value for the duration of the application, but will be different in future
-  // application runs.
+  // Get an estimate of the TimeTick value at the time of the UnixEpoch. Because
+  // Time and TimeTicks respond differently to user-set time and NTP
+  // adjustments, this number is only an estimate. Nevertheless, this can be
+  // useful when you need to relate the value of TimeTicks to a real time and
+  // date. Note: Upon first invocation, this function takes a snapshot of the
+  // realtime clock to establish a reference point.  This function will return
+  // the same value for the duration of the application, but will be different
+  // in future application runs.
   static TimeTicks UnixEpoch();
 
   // Returns |this| snapped to the next tick, given a |tick_phase| and
@@ -738,6 +715,69 @@
 // For logging use only.
 BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks);
 
+// ThreadTicks ----------------------------------------------------------------
+
+// Represents a clock, specific to a particular thread, than runs only while the
+// thread is running.
+class BASE_EXPORT ThreadTicks : public time_internal::TimeBase<ThreadTicks> {
+ public:
+  ThreadTicks() : TimeBase(0) {
+  }
+
+  // Returns true if ThreadTicks::Now() is supported on this system.
+  static bool IsSupported() {
+#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID)
+    return true;
+#elif defined(OS_WIN)
+    return IsSupportedWin();
+#else
+    return false;
+#endif
+  }
+
+  // Waits until the initialization is completed. Needs to be guarded with a
+  // call to IsSupported().
+  static void WaitUntilInitialized() {
+#if defined(OS_WIN)
+    WaitUntilInitializedWin();
+#endif
+  }
+
+  // Returns thread-specific CPU-time on systems that support this feature.
+  // Needs to be guarded with a call to IsSupported(). Use this timer
+  // to (approximately) measure how much time the calling thread spent doing
+  // actual work vs. being de-scheduled. May return bogus results if the thread
+  // migrates to another CPU between two calls. Returns an empty ThreadTicks
+  // object until the initialization is completed. If a clock reading is
+  // absolutely needed, call WaitUntilInitialized() before this method.
+  static ThreadTicks Now();
+
+ private:
+  friend class time_internal::TimeBase<ThreadTicks>;
+
+  // Please use Now() to create a new object. This is for internal use
+  // and testing.
+  explicit ThreadTicks(int64 us) : TimeBase(us) {
+  }
+
+#if defined(OS_WIN)
+  FRIEND_TEST_ALL_PREFIXES(TimeTicks, TSCTicksPerSecond);
+
+  // Returns the frequency of the TSC in ticks per second, or 0 if it hasn't
+  // been measured yet. Needs to be guarded with a call to IsSupported().
+  // This method is declared here rather than in the anonymous namespace to
+  // allow testing.
+  static double TSCTicksPerSecond();
+
+  static bool IsSupportedWin();
+  static void WaitUntilInitializedWin();
+#endif
+};
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks);
+
 }  // namespace base
 
 #endif  // BASE_TIME_TIME_H_
diff --git a/base/time/time_mac.cc b/base/time/time_mac.cc
index e263d07..139e0c9 100644
--- a/base/time/time_mac.cc
+++ b/base/time/time_mac.cc
@@ -8,6 +8,7 @@
 #include <CoreFoundation/CFTimeZone.h>
 #include <mach/mach.h>
 #include <mach/mach_time.h>
+#include <stdint.h>
 #include <sys/sysctl.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -18,10 +19,11 @@
 #include "base/mac/mach_logging.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/mac/scoped_mach_port.h"
+#include "base/numerics/safe_conversions.h"
 
 namespace {
 
-uint64_t ComputeCurrentTicks() {
+int64_t ComputeCurrentTicks() {
 #if defined(OS_IOS)
   // On iOS mach_absolute_time stops while the device is sleeping. Instead use
   // now - KERN_BOOTTIME to get a time difference that is not impacted by clock
@@ -37,8 +39,6 @@
        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
@@ -56,18 +56,19 @@
 
   // 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;
+  base::CheckedNumeric<uint64_t> result(
+      mach_absolute_time() / base::Time::kNanosecondsPerMicrosecond);
+  result *= timebase_info.numer;
+  result /= timebase_info.denom;
 
   // Don't bother with the rollover handling that the Windows version does.
   // With numer and denom = 1 (the expected case), the 64-bit absolute time
   // reported in nanoseconds is enough to last nearly 585 years.
-  return absolute_micro;
+  return base::checked_cast<int64_t>(result.ValueOrDie());
 #endif  // defined(OS_IOS)
 }
 
-uint64_t ComputeThreadTicks() {
+int64_t ComputeThreadTicks() {
 #if defined(OS_IOS)
   NOTREACHED();
   return 0;
@@ -82,15 +83,17 @@
   }
 
   kern_return_t kr = thread_info(
-      thread,
+      thread.get(),
       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;
+  base::CheckedNumeric<int64_t> absolute_micros(
+      thread_info_data.user_time.seconds);
+  absolute_micros *= base::Time::kMicrosecondsPerSecond;
+  absolute_micros += thread_info_data.user_time.microseconds;
+  return absolute_micros.ValueOrDie();
 #endif  // defined(OS_IOS)
 }
 
@@ -114,7 +117,7 @@
 //   => 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 kWindowsEpochDeltaSeconds = INT64_C(11644473600);
 
 // static
 const int64 Time::kWindowsEpochDeltaMicroseconds =
@@ -132,8 +135,8 @@
 
 // static
 Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
-  COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
-                 numeric_limits_infinity_is_undefined_when_not_has_infinity);
+  static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+                "CFAbsoluteTime must have an infinity value");
   if (t == 0)
     return Time();  // Consider 0 as a null Time.
   if (t == std::numeric_limits<CFAbsoluteTime>::infinity())
@@ -144,8 +147,8 @@
 }
 
 CFAbsoluteTime Time::ToCFAbsoluteTime() const {
-  COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
-                 numeric_limits_infinity_is_undefined_when_not_has_infinity);
+  static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+                "CFAbsoluteTime must have an infinity value");
   if (is_null())
     return 0;  // Consider 0 as a null Time.
   if (is_max())
@@ -224,13 +227,8 @@
 }
 
 // static
-TimeTicks TimeTicks::ThreadNow() {
-  return TimeTicks(ComputeThreadTicks());
-}
-
-// static
-TimeTicks TimeTicks::NowFromSystemTraceTime() {
-  return Now();
+ThreadTicks ThreadTicks::Now() {
+  return ThreadTicks(ComputeThreadTicks());
 }
 
 }  // namespace base
diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc
index 8b207eb..d2bb555 100644
--- a/base/time/time_posix.cc
+++ b/base/time/time_posix.cc
@@ -17,7 +17,6 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "base/port.h"
 #include "build/build_config.h"
 
 #if defined(OS_ANDROID)
@@ -81,26 +80,27 @@
 }
 #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.
+int64 ConvertTimespecToMicros(const struct timespec& ts) {
+  base::CheckedNumeric<int64> result(ts.tv_sec);
+  result *= base::Time::kMicrosecondsPerSecond;
+  result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond);
+  return result.ValueOrDie();
+}
+
+// Helper function to get results from clock_gettime() and convert to a
+// microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported
+// on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines
+// _POSIX_MONOTONIC_CLOCK to -1.
 #if (defined(OS_POSIX) &&                                               \
      defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
     defined(OS_BSD) || defined(OS_ANDROID)
-base::TimeTicks ClockNow(clockid_t clk_id) {
-  uint64_t absolute_micro;
-
+int64 ClockNow(clockid_t clk_id) {
   struct timespec ts;
   if (clock_gettime(clk_id, &ts) != 0) {
     NOTREACHED() << "clock_gettime(" << clk_id << ") failed.";
-    return base::TimeTicks();
+    return 0;
   }
-
-  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);
+  return ConvertTimespecToMicros(ts);
 }
 #else  // _POSIX_MONOTONIC_CLOCK
 #error No usable tick clock function on this platform.
@@ -137,7 +137,7 @@
 //   => 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 kWindowsEpochDeltaSeconds = INT64_C(11644473600);
 
 // static
 const int64 Time::kWindowsEpochDeltaMicroseconds =
@@ -310,7 +310,7 @@
 // TimeTicks ------------------------------------------------------------------
 // static
 TimeTicks TimeTicks::Now() {
-  return ClockNow(CLOCK_MONOTONIC);
+  return TimeTicks(ClockNow(CLOCK_MONOTONIC));
 }
 
 // static
@@ -319,44 +319,16 @@
 }
 
 // static
-TimeTicks TimeTicks::ThreadNow() {
+ThreadTicks ThreadTicks::Now() {
 #if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
     defined(OS_ANDROID)
-  return ClockNow(CLOCK_THREAD_CPUTIME_ID);
+  return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
 #else
   NOTREACHED();
-  return TimeTicks();
+  return ThreadTicks();
 #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
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index 456782c..868a546 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -4,8 +4,8 @@
 
 #include "base/time/time.h"
 
+#include <stdint.h>
 #include <time.h>
-
 #include <limits>
 #include <string>
 
@@ -484,52 +484,6 @@
   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());
@@ -690,15 +644,16 @@
 #else
 #define MAYBE_ThreadNow ThreadNow
 #endif
-TEST(TimeTicks, MAYBE_ThreadNow) {
-  if (TimeTicks::IsThreadNowSupported()) {
+TEST(ThreadTicks, MAYBE_ThreadNow) {
+  if (ThreadTicks::IsSupported()) {
+    ThreadTicks::WaitUntilInitialized();
     TimeTicks begin = TimeTicks::Now();
-    TimeTicks begin_thread = TimeTicks::ThreadNow();
+    ThreadTicks begin_thread = ThreadTicks::Now();
     // Make sure that ThreadNow value is non-zero.
-    EXPECT_GT(begin_thread, TimeTicks());
+    EXPECT_GT(begin_thread, ThreadTicks());
     // Sleep for 10 milliseconds to get the thread de-scheduled.
     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
-    TimeTicks end_thread = TimeTicks::ThreadNow();
+    ThreadTicks end_thread = ThreadTicks::Now();
     TimeTicks end = TimeTicks::Now();
     TimeDelta delta = end - begin;
     TimeDelta delta_thread = end_thread - begin_thread;
@@ -710,11 +665,6 @@
   }
 }
 
-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::FromMicroseconds(1000);
@@ -794,6 +744,7 @@
   EXPECT_EQ(13, TimeDelta::FromMillisecondsD(13.3).InMilliseconds());
   EXPECT_EQ(13.3, TimeDelta::FromMillisecondsD(13.3).InMillisecondsF());
   EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).InMicroseconds());
+  EXPECT_EQ(3.456, TimeDelta::FromMillisecondsD(3.45678).InMillisecondsF());
 }
 
 #if defined(OS_POSIX)
@@ -832,7 +783,7 @@
   exploded.millisecond = 0;
   Time t = Time::FromUTCExploded(exploded);
   // Unix 1970 epoch.
-  EXPECT_EQ(GG_INT64_C(11644473600000000), t.ToInternalValue());
+  EXPECT_EQ(INT64_C(11644473600000000), t.ToInternalValue());
 
   // We can't test 1601 epoch, since the system time functions on Linux
   // only compute years starting from 1900.
@@ -867,6 +818,83 @@
             TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude());
 }
 
+TEST(TimeDelta, Max) {
+  TimeDelta max = TimeDelta::Max();
+  EXPECT_TRUE(max.is_max());
+  EXPECT_EQ(max, TimeDelta::Max());
+  EXPECT_GT(max, TimeDelta::FromDays(100 * 365));
+  EXPECT_GT(max, TimeDelta());
+}
+
+bool IsMin(TimeDelta delta) {
+  return (-delta).is_max();
+}
+
+TEST(TimeDelta, MaxConversions) {
+  TimeDelta t = TimeDelta::Max();
+  EXPECT_EQ(std::numeric_limits<int64>::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());
+
+  int64 max_int = std::numeric_limits<int64>::max();
+
+  t = TimeDelta::FromSeconds(max_int / Time::kMicrosecondsPerSecond + 1);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMilliseconds(max_int / Time::kMillisecondsPerSecond + 1);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMicroseconds(max_int);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromSeconds(-max_int / Time::kMicrosecondsPerSecond - 1);
+  EXPECT_TRUE(IsMin(t));
+
+  t = TimeDelta::FromMilliseconds(-max_int / Time::kMillisecondsPerSecond - 1);
+  EXPECT_TRUE(IsMin(t));
+
+  t = TimeDelta::FromMicroseconds(-max_int);
+  EXPECT_TRUE(IsMin(t));
+
+  t = -TimeDelta::FromMicroseconds(std::numeric_limits<int64>::min());
+  EXPECT_FALSE(IsMin(t));
+
+  t = TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+
+  double max_d = max_int;
+
+  t = TimeDelta::FromSecondsD(max_d / Time::kMicrosecondsPerSecond + 1);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMillisecondsD(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMillisecondsD(max_d / Time::kMillisecondsPerSecond * 2);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromSecondsD(-max_d / Time::kMicrosecondsPerSecond - 1);
+  EXPECT_TRUE(IsMin(t));
+
+  t = TimeDelta::FromMillisecondsD(-max_d / Time::kMillisecondsPerSecond * 2);
+  EXPECT_TRUE(IsMin(t));
+}
 
 TEST(TimeDelta, NumericOperators) {
   double d = 0.5;
@@ -893,7 +921,6 @@
   EXPECT_EQ(TimeDelta::FromMilliseconds(500),
             f * TimeDelta::FromMilliseconds(1000));
 
-
   int i = 2;
   EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
             TimeDelta::FromMilliseconds(1000) * i);
@@ -918,7 +945,6 @@
   EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
             i64 * TimeDelta::FromMilliseconds(1000));
 
-
   EXPECT_EQ(TimeDelta::FromMilliseconds(500),
             TimeDelta::FromMilliseconds(1000) * 0.5);
   EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
@@ -942,10 +968,6 @@
             2 * TimeDelta::FromMilliseconds(1000));
 }
 
-bool IsMin(TimeDelta delta) {
-  return (-delta).is_max();
-}
-
 TEST(TimeDelta, Overflows) {
   // Some sanity checks.
   EXPECT_TRUE(TimeDelta::Max().is_max());
diff --git a/base/time/time_win.cc b/base/time/time_win.cc
index d2403f2..9584127 100644
--- a/base/time/time_win.cc
+++ b/base/time/time_win.cc
@@ -36,6 +36,7 @@
 #pragma comment(lib, "winmm.lib")
 #include <windows.h>
 #include <mmsystem.h>
+#include <stdint.h>
 
 #include "base/basictypes.h"
 #include "base/cpu.h"
@@ -43,6 +44,7 @@
 #include "base/logging.h"
 #include "base/synchronization/lock.h"
 
+using base::ThreadTicks;
 using base::Time;
 using base::TimeDelta;
 using base::TimeTicks;
@@ -53,7 +55,7 @@
 // 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
+  // 100-nanoseconds to microseconds. This only works on little-endian
   // machines.
   return bit_cast<int64, FILETIME>(ft) / 10;
 }
@@ -62,7 +64,7 @@
   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
+  // Multiply by 10 to convert microseconds to 100-nanoseconds. Bit_cast will
   // handle alignment problems. This only works on little-endian machines.
   *ft = bit_cast<FILETIME, int64>(us * 10);
 }
@@ -97,6 +99,26 @@
 base::LazyInstance<base::Lock>::Leaky g_high_res_lock =
     LAZY_INSTANCE_INITIALIZER;
 
+// Returns a pointer to the QueryThreadCycleTime() function from Windows.
+// Can't statically link to it because it is not available on XP.
+using QueryThreadCycleTimePtr = decltype(::QueryThreadCycleTime)*;
+QueryThreadCycleTimePtr GetQueryThreadCycleTimeFunction() {
+  static const QueryThreadCycleTimePtr query_thread_cycle_time_fn =
+      reinterpret_cast<QueryThreadCycleTimePtr>(::GetProcAddress(
+          ::GetModuleHandle(L"kernel32.dll"), "QueryThreadCycleTime"));
+  return query_thread_cycle_time_fn;
+}
+
+// Returns the current value of the performance counter.
+uint64 QPCNowRaw() {
+  LARGE_INTEGER perf_counter_now = {};
+  // According to the MSDN documentation for QueryPerformanceCounter(), this
+  // will never fail on systems that run XP or later.
+  // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
+  ::QueryPerformanceCounter(&perf_counter_now);
+  return perf_counter_now.QuadPart;
+}
+
 }  // namespace
 
 // Time -----------------------------------------------------------------------
@@ -106,7 +128,7 @@
 // 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);
+const int64 Time::kTimeTToMicrosecondsOffset = INT64_C(11644473600000000);
 
 // static
 Time Time::Now() {
@@ -328,7 +350,7 @@
 // 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() {
+TimeDelta RolloverProtectedNow() {
   base::AutoLock locked(g_rollover_lock);
   // We should hold the lock while calling tick_function to make sure that
   // we keep last_seen_now stay correctly in sync.
@@ -336,7 +358,7 @@
   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);
+  return TimeDelta::FromMilliseconds(now + g_rollover_ms);
 }
 
 // Discussion of tick counter options on Windows:
@@ -374,15 +396,13 @@
 // this timer; and also other Windows applications can alter it, affecting this
 // one.
 
-using NowFunction = TimeTicks (*)(void);
+using NowFunction = TimeDelta (*)(void);
 
-TimeTicks InitialNowFunction();
-TimeTicks InitialSystemTraceNowFunction();
+TimeDelta InitialNowFunction();
 
-// See "threading notes" in InitializeNowFunctionPointers() for details on how
+// See "threading notes" in InitializeNowFunctionPointer() 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
@@ -392,7 +412,7 @@
 
 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
   // Ensure that the assignment to |g_qpc_ticks_per_second|, made in
-  // InitializeNowFunctionPointers(), has happened by this point.
+  // InitializeNowFunctionPointer(), has happened by this point.
   ATOMIC_THREAD_FENCE(memory_order_acquire);
 
   DCHECK_GT(g_qpc_ticks_per_second, 0);
@@ -413,10 +433,8 @@
        g_qpc_ticks_per_second));
 }
 
-TimeTicks QPCNow() {
-  LARGE_INTEGER now;
-  QueryPerformanceCounter(&now);
-  return TimeTicks() + QPCValueToTimeDelta(now.QuadPart);
+TimeDelta QPCNow() {
+  return QPCValueToTimeDelta(QPCNowRaw());
 }
 
 bool IsBuggyAthlon(const base::CPU& cpu) {
@@ -424,37 +442,33 @@
   return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
 }
 
-void InitializeNowFunctionPointers() {
-  LARGE_INTEGER ticks_per_sec = {0};
+void InitializeNowFunctionPointer() {
+  LARGE_INTEGER ticks_per_sec = {};
   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 Windows cannot provide a QPC implementation, TimeTicks::Now() 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.
+  // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now()
+  // will still use the low-resolution clock. 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.
+  // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015,
+  // ~72% 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)) {
+  if (ticks_per_sec.QuadPart <= 0 ||
+      !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;
+    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
+  // more threads to enter InitializeNowFunctionPointer() in parallel. This is
   // not a problem since all threads should end up writing out the same values
   // to the global variables.
   //
@@ -465,19 +479,13 @@
   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();
+TimeDelta InitialNowFunction() {
+  InitializeNowFunctionPointer();
   return g_now_function();
 }
 
-TimeTicks InitialSystemTraceNowFunction() {
-  InitializeNowFunctionPointers();
-  return g_system_trace_now_function();
-}
-
 }  // namespace
 
 // static
@@ -493,25 +501,106 @@
 
 // static
 TimeTicks TimeTicks::Now() {
-  return g_now_function();
+  return TimeTicks() + g_now_function();
 }
 
 // static
 bool TimeTicks::IsHighResolution() {
   if (g_now_function == &InitialNowFunction)
-    InitializeNowFunctionPointers();
+    InitializeNowFunctionPointer();
   return g_now_function == &QPCNow;
 }
 
 // static
-TimeTicks TimeTicks::ThreadNow() {
-  NOTREACHED();
-  return TimeTicks();
+ThreadTicks ThreadTicks::Now() {
+  DCHECK(IsSupported());
+
+  // Get the number of TSC ticks used by the current thread.
+  ULONG64 thread_cycle_time = 0;
+  GetQueryThreadCycleTimeFunction()(::GetCurrentThread(), &thread_cycle_time);
+
+  // Get the frequency of the TSC.
+  double tsc_ticks_per_second = TSCTicksPerSecond();
+  if (tsc_ticks_per_second == 0)
+    return ThreadTicks();
+
+  // Return the CPU time of the current thread.
+  double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
+  return ThreadTicks(static_cast<int64>(
+      thread_time_seconds * Time::kMicrosecondsPerSecond));
 }
 
 // static
-TimeTicks TimeTicks::NowFromSystemTraceTime() {
-  return g_system_trace_now_function();
+bool ThreadTicks::IsSupportedWin() {
+  static bool is_supported = GetQueryThreadCycleTimeFunction() &&
+                             base::CPU().has_non_stop_time_stamp_counter() &&
+                             !IsBuggyAthlon(base::CPU());
+  return is_supported;
+}
+
+// static
+void ThreadTicks::WaitUntilInitializedWin() {
+  while (TSCTicksPerSecond() == 0)
+    ::Sleep(10);
+}
+
+double ThreadTicks::TSCTicksPerSecond() {
+  DCHECK(IsSupported());
+
+  // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
+  // frequency, because there is no guarantee that the TSC frequency is equal to
+  // the performance counter frequency.
+
+  // The TSC frequency is cached in a static variable because it takes some time
+  // to compute it.
+  static double tsc_ticks_per_second = 0;
+  if (tsc_ticks_per_second != 0)
+    return tsc_ticks_per_second;
+
+  // Increase the thread priority to reduces the chances of having a context
+  // switch during a reading of the TSC and the performance counter.
+  int previous_priority = ::GetThreadPriority(::GetCurrentThread());
+  ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+
+  // The first time that this function is called, make an initial reading of the
+  // TSC and the performance counter.
+  static const uint64 tsc_initial = __rdtsc();
+  static const uint64 perf_counter_initial = QPCNowRaw();
+
+  // Make a another reading of the TSC and the performance counter every time
+  // that this function is called.
+  uint64 tsc_now = __rdtsc();
+  uint64 perf_counter_now = QPCNowRaw();
+
+  // Reset the thread priority.
+  ::SetThreadPriority(::GetCurrentThread(), previous_priority);
+
+  // Make sure that at least 50 ms elapsed between the 2 readings. The first
+  // time that this function is called, we don't expect this to be the case.
+  // Note: The longer the elapsed time between the 2 readings is, the more
+  //   accurate the computed TSC frequency will be. The 50 ms value was
+  //   chosen because local benchmarks show that it allows us to get a
+  //   stddev of less than 1 tick/us between multiple runs.
+  // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
+  //   this will never fail on systems that run XP or later.
+  //   https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
+  LARGE_INTEGER perf_counter_frequency = {};
+  ::QueryPerformanceFrequency(&perf_counter_frequency);
+  DCHECK_GE(perf_counter_now, perf_counter_initial);
+  uint64 perf_counter_ticks = perf_counter_now - perf_counter_initial;
+  double elapsed_time_seconds =
+      perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
+
+  const double kMinimumEvaluationPeriodSeconds = 0.05;
+  if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
+    return 0;
+
+  // Compute the frequency of the TSC.
+  DCHECK_GE(tsc_now, tsc_initial);
+  uint64 tsc_ticks = tsc_now - tsc_initial;
+  tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
+
+  return tsc_ticks_per_second;
 }
 
 // static
diff --git a/base/time/time_win_unittest.cc b/base/time/time_win_unittest.cc
index 82be8c5..baaa322 100644
--- a/base/time/time_win_unittest.cc
+++ b/base/time/time_win_unittest.cc
@@ -12,12 +12,10 @@
 
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
+#include "base/win/registry.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using base::Time;
-using base::TimeDelta;
-using base::TimeTicks;
-
+namespace base {
 namespace {
 
 class MockTimeTicks : public TimeTicks {
@@ -65,7 +63,14 @@
 
 }  // namespace
 
-TEST(TimeTicks, WinRollover) {
+// This test spawns many threads, and can occasionally fail due to resource
+// exhaustion in the presence of ASan.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_WinRollover DISABLED_WinRollover
+#else
+#define MAYBE_WinRollover WinRollover
+#endif
+TEST(TimeTicks, MAYBE_WinRollover) {
   // The internal counter rolls over at ~49days.  We'll use a mock
   // timer to test this case.
   // Basic test algorithm:
@@ -182,20 +187,22 @@
   };
   // 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, "" }
-  };
+  static_assert(sizeof(TimeTicks) == sizeof(Time),
+                "TimeTicks and Time must be the same size");
+  std::vector<TestCase> cases;
+  cases.push_back({reinterpret_cast<TestFunc>(&Time::Now), "Time::Now"});
+  cases.push_back({&TimeTicks::Now, "TimeTicks::Now"});
 
-  int test_case = 0;
-  while (cases[test_case].func) {
+  if (ThreadTicks::IsSupported()) {
+    ThreadTicks::WaitUntilInitialized();
+    cases.push_back(
+        {reinterpret_cast<TestFunc>(&ThreadTicks::Now), "ThreadTicks::Now"});
+  }
+
+  for (const auto& test_case : cases) {
     TimeTicks start = TimeTicks::Now();
     for (int index = 0; index < kLoops; index++)
-      cases[test_case].func();
+      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
@@ -205,9 +212,29 @@
     // 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++;
+    printf("%s: %1.2fus per call\n", test_case.description,
+           (stop - start).InMillisecondsF() * 1000 / kLoops);
+  }
+}
+
+TEST(TimeTicks, TSCTicksPerSecond) {
+  if (ThreadTicks::IsSupported()) {
+    ThreadTicks::WaitUntilInitialized();
+
+    // Read the CPU frequency from the registry.
+    base::win::RegKey processor_key(
+        HKEY_LOCAL_MACHINE,
+        L"Hardware\\Description\\System\\CentralProcessor\\0", KEY_QUERY_VALUE);
+    ASSERT_TRUE(processor_key.Valid());
+    DWORD processor_mhz_from_registry;
+    ASSERT_EQ(ERROR_SUCCESS,
+              processor_key.ReadValueDW(L"~MHz", &processor_mhz_from_registry));
+
+    // Expect the measured TSC frequency to be similar to the processor
+    // frequency from the registry (0.5% error).
+    double tsc_mhz_measured = ThreadTicks::TSCTicksPerSecond() / 1e6;
+    EXPECT_NEAR(tsc_mhz_measured, processor_mhz_from_registry,
+                0.005 * processor_mhz_from_registry);
   }
 }
 
@@ -265,3 +292,5 @@
         << (ticks < Time::kQPCOverflowThreshold ? "FAST" : "SAFE");
   }
 }
+
+}  // namespace base
diff --git a/base/timer/hi_res_timer_manager_unittest.cc b/base/timer/hi_res_timer_manager_unittest.cc
index 5475a91..4fc48b5 100644
--- a/base/timer/hi_res_timer_manager_unittest.cc
+++ b/base/timer/hi_res_timer_manager_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "base/timer/hi_res_timer_manager.h"
 
+#include <utility>
+
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/power_monitor/power_monitor.h"
@@ -22,7 +24,7 @@
   scoped_ptr<base::PowerMonitorSource> power_monitor_source(
       new base::PowerMonitorDeviceSource());
   scoped_ptr<base::PowerMonitor> power_monitor(
-      new base::PowerMonitor(power_monitor_source.Pass()));
+      new base::PowerMonitor(std::move(power_monitor_source)));
 
   HighResolutionTimerManager manager;
   // Simulate a on-AC power event to get to a known initial state.
diff --git a/base/timer/timer.h b/base/timer/timer.h
index 1ef58a3..c5bd9ce 100644
--- a/base/timer/timer.h
+++ b/base/timer/timer.h
@@ -29,7 +29,7 @@
 //       // This method is called every second to do stuff.
 //       ...
 //     }
-//     base::RepeatingTimer<MyClass> timer_;
+//     base::RepeatingTimer timer_;
 //   };
 //
 // Both OneShotTimer and RepeatingTimer also support a Reset method, which
@@ -200,11 +200,8 @@
 //-----------------------------------------------------------------------------
 // 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
@@ -212,15 +209,18 @@
   // see bug 148832.
   using Timer::Start;
 
-  BaseTimerMethodPointer() : Timer(kIsRepeating, kIsRepeating) {}
+  enum RepeatMode { ONE_SHOT, REPEATING };
+  BaseTimerMethodPointer(RepeatMode mode)
+      : Timer(mode == REPEATING, mode == REPEATING) {}
 
   // Start the timer to run at the given |delay| from now. If the timer is
   // already running, it will be replaced to call a task formed from
   // |reviewer->*method|.
-  virtual void Start(const tracked_objects::Location& posted_from,
-                     TimeDelta delay,
-                     Receiver* receiver,
-                     ReceiverMethod method) {
+  template <class Receiver>
+  void Start(const tracked_objects::Location& posted_from,
+             TimeDelta delay,
+             Receiver* receiver,
+             void (Receiver::*method)()) {
     Timer::Start(posted_from, delay,
                  base::Bind(method, base::Unretained(receiver)));
   }
@@ -228,13 +228,17 @@
 
 //-----------------------------------------------------------------------------
 // A simple, one-shot timer.  See usage notes at the top of the file.
-template <class Receiver>
-class OneShotTimer : public BaseTimerMethodPointer<Receiver, false> {};
+class OneShotTimer : public BaseTimerMethodPointer {
+ public:
+  OneShotTimer() : BaseTimerMethodPointer(ONE_SHOT) {}
+};
 
 //-----------------------------------------------------------------------------
 // A simple, repeating timer.  See usage notes at the top of the file.
-template <class Receiver>
-class RepeatingTimer : public BaseTimerMethodPointer<Receiver, true> {};
+class RepeatingTimer : public BaseTimerMethodPointer {
+ public:
+  RepeatingTimer() : BaseTimerMethodPointer(REPEATING) {}
+};
 
 //-----------------------------------------------------------------------------
 // A Delay timer is like The Button from Lost. Once started, you have to keep
@@ -247,22 +251,29 @@
 //
 // 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)();
-
+  template <class Receiver>
   DelayTimer(const tracked_objects::Location& posted_from,
              TimeDelta delay,
              Receiver* receiver,
-             ReceiverMethod method)
-      : Timer(posted_from, delay,
+             void (Receiver::*method)())
+      : Timer(posted_from,
+              delay,
               base::Bind(method, base::Unretained(receiver)),
               false) {}
 
-  void Reset() override { Timer::Reset(); }
+  void Reset() override;
 };
 
+// This class has a templated method so it can not be exported without failing
+// to link in MSVC. But clang-plugin does not allow inline definitions of
+// virtual methods, so the inline definition lives in the header file here
+// to satisfy both.
+inline void DelayTimer::Reset() {
+  Timer::Reset();
+}
+
 }  // namespace base
 
 #endif  // BASE_TIMER_TIMER_H_
diff --git a/base/timer/timer_unittest.cc b/base/timer/timer_unittest.cc
index 7213b80..35e4315 100644
--- a/base/timer/timer_unittest.cc
+++ b/base/timer/timer_unittest.cc
@@ -51,17 +51,15 @@
   }
 
   bool* did_run_;
-  base::OneShotTimer<OneShotTimerTester> timer_;
+  base::OneShotTimer timer_;
   const unsigned delay_ms_;
   bool quit_message_loop_;
 };
 
 class OneShotSelfDeletingTimerTester {
  public:
-  explicit OneShotSelfDeletingTimerTester(bool* did_run) :
-      did_run_(did_run),
-      timer_(new base::OneShotTimer<OneShotSelfDeletingTimerTester>()) {
-  }
+  explicit OneShotSelfDeletingTimerTester(bool* did_run)
+      : did_run_(did_run), timer_(new base::OneShotTimer()) {}
 
   void Start() {
     timer_->Start(FROM_HERE, TimeDelta::FromMilliseconds(10), this,
@@ -76,7 +74,7 @@
   }
 
   bool* did_run_;
-  scoped_ptr<base::OneShotTimer<OneShotSelfDeletingTimerTester> > timer_;
+  scoped_ptr<base::OneShotTimer> timer_;
 };
 
 class RepeatingTimerTester {
@@ -101,7 +99,7 @@
   bool* did_run_;
   int counter_;
   TimeDelta delay_;
-  base::RepeatingTimer<RepeatingTimerTester> timer_;
+  base::RepeatingTimer timer_;
 };
 
 void RunTest_OneShotTimer(base::MessageLoop::Type message_loop_type) {
@@ -205,8 +203,8 @@
 
   // 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);
+  base::DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target,
+                         &DelayTimerTarget::Signal);
 
   bool did_run = false;
   OneShotTimerTester tester(&did_run);
@@ -220,8 +218,8 @@
   base::MessageLoop loop(message_loop_type);
 
   DelayTimerTarget target;
-  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
-      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+  base::DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target,
+                         &DelayTimerTarget::Signal);
   timer.Reset();
 
   bool did_run = false;
@@ -233,11 +231,8 @@
 }
 
 struct ResetHelper {
-  ResetHelper(base::DelayTimer<DelayTimerTarget>* timer,
-              DelayTimerTarget* target)
-      : timer_(timer),
-        target_(target) {
-  }
+  ResetHelper(base::DelayTimer* timer, DelayTimerTarget* target)
+      : timer_(timer), target_(target) {}
 
   void Reset() {
     ASSERT_FALSE(target_->signaled());
@@ -245,8 +240,8 @@
   }
 
  private:
-  base::DelayTimer<DelayTimerTarget> *const timer_;
-  DelayTimerTarget *const target_;
+  base::DelayTimer* const timer_;
+  DelayTimerTarget* const target_;
 };
 
 void RunTest_DelayTimer_Reset(base::MessageLoop::Type message_loop_type) {
@@ -254,13 +249,13 @@
 
   // 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);
+  base::DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
+                         &DelayTimerTarget::Signal);
   timer.Reset();
 
   ResetHelper reset_helper(&timer, &target);
 
-  base::OneShotTimer<ResetHelper> timers[20];
+  base::OneShotTimer timers[20];
   for (size_t i = 0; i < arraysize(timers); ++i) {
     timers[i].Start(FROM_HERE, TimeDelta::FromMilliseconds(i * 10),
                     &reset_helper, &ResetHelper::Reset);
@@ -288,9 +283,8 @@
   DelayTimerFatalTarget target;
 
   {
-    base::DelayTimer<DelayTimerFatalTarget> timer(
-        FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
-        &DelayTimerFatalTarget::Signal);
+    base::DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
+                           &DelayTimerFatalTarget::Signal);
     timer.Reset();
   }
 
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc
index 2ddaf89..4340fcd 100644
--- a/base/tools_sanity_unittest.cc
+++ b/base/tools_sanity_unittest.cc
@@ -145,6 +145,12 @@
   HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
 }
 
+static int* allocateArray() {
+  // Clang warns about the mismatched new[]/delete if they occur in the same
+  // function.
+  return new int[10];
+}
+
 TEST(ToolsSanityTest, MAYBE_ArrayDeletedWithoutBraces) {
 #if !defined(ADDRESS_SANITIZER) && !defined(SYZYASAN)
   // This test may corrupt memory if not run under Valgrind or compiled with
@@ -154,10 +160,16 @@
 #endif
 
   // Without the |volatile|, clang optimizes away the next two lines.
-  int* volatile foo = new int[10];
+  int* volatile foo = allocateArray();
   delete foo;
 }
 
+static int* allocateScalar() {
+  // Clang warns about the mismatched new/delete[] if they occur in the same
+  // function.
+  return new int;
+}
+
 TEST(ToolsSanityTest, MAYBE_SingleElementDeletedWithBraces) {
 #if !defined(ADDRESS_SANITIZER)
   // This test may corrupt memory if not run under Valgrind or compiled with
@@ -167,7 +179,7 @@
 #endif
 
   // Without the |volatile|, clang optimizes away the next two lines.
-  int* volatile foo = new int;
+  int* volatile foo = allocateScalar();
   (void) foo;
   delete [] foo;
 }
@@ -327,4 +339,19 @@
   EXPECT_EQ(kMagicValue, shared);
 }
 
+#if defined(CFI_ENFORCEMENT)
+TEST(ToolsSanityTest, BadCast) {
+  class A {
+    virtual void f() {}
+  };
+
+  class B {
+    virtual void f() {}
+  };
+
+  A a;
+  EXPECT_DEATH((void)(B*)&a, "ILL_ILLOPN");
+}
+#endif
+
 }  // namespace base
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index 633ab90..85c26e2 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -4,13 +4,31 @@
 
 source_set("trace_event") {
   sources = [
+    "common/trace_event_common.h",
+    "heap_profiler_allocation_context.cc",
+    "heap_profiler_allocation_context.h",
+    "heap_profiler_allocation_context_tracker.cc",
+    "heap_profiler_allocation_context_tracker.h",
+    "heap_profiler_allocation_register.cc",
+    "heap_profiler_allocation_register.h",
+    "heap_profiler_allocation_register_posix.cc",
+    "heap_profiler_allocation_register_win.cc",
+    "heap_profiler_heap_dump_writer.cc",
+    "heap_profiler_heap_dump_writer.h",
+    "heap_profiler_stack_frame_deduplicator.cc",
+    "heap_profiler_stack_frame_deduplicator.h",
+    "heap_profiler_type_name_deduplicator.cc",
+    "heap_profiler_type_name_deduplicator.h",
     "java_heap_dump_provider_android.cc",
     "java_heap_dump_provider_android.h",
     "memory_allocator_dump.cc",
     "memory_allocator_dump.h",
+    "memory_allocator_dump_guid.cc",
+    "memory_allocator_dump_guid.h",
     "memory_dump_manager.cc",
     "memory_dump_manager.h",
     "memory_dump_provider.h",
+    "memory_dump_request_args.cc",
     "memory_dump_request_args.h",
     "memory_dump_session_state.cc",
     "memory_dump_session_state.h",
@@ -18,12 +36,15 @@
     "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_buffer.cc",
+    "trace_buffer.h",
+    "trace_config.cc",
+    "trace_config.h",
     "trace_event.h",
     "trace_event_android.cc",
     "trace_event_argument.cc",
@@ -32,33 +53,21 @@
     "trace_event_etw_export_win.h",
     "trace_event_impl.cc",
     "trace_event_impl.h",
-    "trace_event_impl_constants.cc",
-    "trace_event_memory.cc",
-    "trace_event_memory.h",
+    "trace_event_memory_overhead.cc",
+    "trace_event_memory_overhead.h",
     "trace_event_synthetic_delay.cc",
     "trace_event_synthetic_delay.h",
     "trace_event_system_stats_monitor.cc",
     "trace_event_system_stats_monitor.h",
-    "trace_event_win.cc",
-    "trace_event_win.h",
+    "trace_log.cc",
+    "trace_log.h",
+    "trace_log_constants.cc",
+    "trace_sampling_thread.cc",
+    "trace_sampling_thread.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 = [
@@ -69,6 +78,24 @@
     "//base/third_party/dynamic_annotations",
   ]
 
+  if (is_nacl) {
+    sources -= [
+      "process_memory_totals_dump_provider.cc",
+      "trace_event_system_stats_monitor.cc",
+    ]
+  }
+
+  if (is_linux || is_android || is_mac) {
+    sources += [
+      "malloc_dump_provider.cc",
+      "malloc_dump_provider.h",
+    ]
+    deps += [ "//base/allocator:extension_thunks" ]
+  }
+
+  if (is_linux || is_android) {
+    sources += [ "process_memory_maps_dump_provider.cc" ]
+  }
   if (is_win) {
     deps += [ "//base/trace_event/etw_manifest:chrome_events_win" ]
   }
@@ -85,20 +112,33 @@
 source_set("trace_event_unittests") {
   testonly = true
   sources = [
+    "heap_profiler_allocation_context_tracker_unittest.cc",
+    "heap_profiler_allocation_register_unittest.cc",
+    "heap_profiler_heap_dump_writer_unittest.cc",
+    "heap_profiler_stack_frame_deduplicator_unittest.cc",
+    "heap_profiler_type_name_deduplicator_unittest.cc",
     "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_dump_unittest.cc",
     "process_memory_totals_dump_provider_unittest.cc",
+    "trace_config_memory_test_util.h",
+    "trace_config_unittest.cc",
     "trace_event_argument_unittest.cc",
-    "trace_event_memory_unittest.cc",
     "trace_event_synthetic_delay_unittest.cc",
     "trace_event_system_stats_monitor_unittest.cc",
     "trace_event_unittest.cc",
-    "trace_event_win_unittest.cc",
     "winheap_dump_provider_win_unittest.cc",
   ]
 
+  if (is_linux || is_android) {
+    sources += [ "process_memory_maps_dump_provider_unittest.cc" ]
+  }
+
+  if (is_android) {
+    sources += [ "trace_event_android_unittest.cc" ]
+  }
+
   deps = [
     "//base/test:test_support",
     "//testing/gmock",
diff --git a/base/trace_event/OWNERS b/base/trace_event/OWNERS
index aa1d675..9160267 100644
--- a/base/trace_event/OWNERS
+++ b/base/trace_event/OWNERS
@@ -1,4 +1,6 @@
-nduca@chromium.org
 dsinclair@chromium.org
+nduca@chromium.org
+oysteine@chromium.org
 primiano@chromium.org
+simonhatch@chromium.org
 per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/base/trace_event/common/trace_event_common.h b/base/trace_event/common/trace_event_common.h
new file mode 100644
index 0000000..72202f3
--- /dev/null
+++ b/base/trace_event/common/trace_event_common.h
@@ -0,0 +1,1054 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This header file defines the set of trace_event macros without specifying
+// how the events actually get collected and stored. If you need to expose trace
+// events to some other universe, you can copy-and-paste this file as well as
+// trace_event.h, modifying the macros contained there as necessary for the
+// target platform. The end result is that multiple libraries can funnel events
+// through to a shared trace event collector.
+
+// IMPORTANT: To avoid conflicts, if you need to modify this file for a library,
+// land your change in base/ first, and then copy-and-paste it.
+
+// Trace events are for tracking application performance and resource usage.
+// Macros are provided to track:
+//    Begin and end of function calls
+//    Counters
+//
+// Events are issued against categories. Whereas LOG's
+// categories are statically defined, TRACE categories are created
+// implicitly with a string. For example:
+//   TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent",
+//                        TRACE_EVENT_SCOPE_THREAD)
+//
+// It is often the case that one trace may belong in multiple categories at the
+// same time. The first argument to the trace can be a comma-separated list of
+// categories, forming a category group, like:
+//
+// TRACE_EVENT_INSTANT0("input,views", "OnMouseOver", TRACE_EVENT_SCOPE_THREAD)
+//
+// We can enable/disable tracing of OnMouseOver by enabling/disabling either
+// category.
+//
+// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope:
+//   TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly")
+//   doSomethingCostly()
+//   TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly")
+// Note: our tools can't always determine the correct BEGIN/END pairs unless
+// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you
+// need them to be in separate scopes.
+//
+// A common use case is to trace entire function scopes. This
+// issues a trace BEGIN and END automatically:
+//   void doSomethingCostly() {
+//     TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly");
+//     ...
+//   }
+//
+// Additional parameters can be associated with an event:
+//   void doSomethingCostly2(int howMuch) {
+//     TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly",
+//         "howMuch", howMuch);
+//     ...
+//   }
+//
+// The trace system will automatically add to this information the
+// current process id, thread id, and a timestamp in microseconds.
+//
+// To trace an asynchronous procedure such as an IPC send/receive, use
+// ASYNC_BEGIN and ASYNC_END:
+//   [single threaded sender code]
+//     static int send_count = 0;
+//     ++send_count;
+//     TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count);
+//     Send(new MyMessage(send_count));
+//   [receive code]
+//     void OnMyMessage(send_count) {
+//       TRACE_EVENT_ASYNC_END0("ipc", "message", send_count);
+//     }
+// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs.
+// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process.
+// Pointers can be used for the ID parameter, and they will be mangled
+// internally so that the same pointer on two different processes will not
+// match. For example:
+//   class MyTracedClass {
+//    public:
+//     MyTracedClass() {
+//       TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this);
+//     }
+//     ~MyTracedClass() {
+//       TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this);
+//     }
+//   }
+//
+// Trace event also supports counters, which is a way to track a quantity
+// as it varies over time. Counters are created with the following macro:
+//   TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue);
+//
+// Counters are process-specific. The macro itself can be issued from any
+// thread, however.
+//
+// Sometimes, you want to track two counters at once. You can do this with two
+// counter macros:
+//   TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]);
+//   TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]);
+// Or you can do it with a combined macro:
+//   TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter",
+//       "bytesPinned", g_myCounterValue[0],
+//       "bytesAllocated", g_myCounterValue[1]);
+// This indicates to the tracing UI that these counters should be displayed
+// in a single graph, as a summed area chart.
+//
+// Since counters are in a global namespace, you may want to disambiguate with a
+// unique ID, by using the TRACE_COUNTER_ID* variations.
+//
+// By default, trace collection is compiled in, but turned off at runtime.
+// Collecting trace data is the responsibility of the embedding
+// application. In Chrome's case, navigating to about:tracing will turn on
+// tracing and display data collected across all active processes.
+//
+//
+// Memory scoping note:
+// Tracing copies the pointers, not the string content, of the strings passed
+// in for category_group, name, and arg_names.  Thus, the following code will
+// cause problems:
+//     char* str = strdup("importantName");
+//     TRACE_EVENT_INSTANT0("SUBSYSTEM", str);  // BAD!
+//     free(str);                   // Trace system now has dangling pointer
+//
+// To avoid this issue with the |name| and |arg_name| parameters, use the
+// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead.
+// Notes: The category must always be in a long-lived char* (i.e. static const).
+//        The |arg_values|, when used, are always deep copied with the _COPY
+//        macros.
+//
+// When are string argument values copied:
+// const char* arg_values are only referenced by default:
+//     TRACE_EVENT1("category", "name",
+//                  "arg1", "literal string is only referenced");
+// Use TRACE_STR_COPY to force copying of a const char*:
+//     TRACE_EVENT1("category", "name",
+//                  "arg1", TRACE_STR_COPY("string will be copied"));
+// std::string arg_values are always copied:
+//     TRACE_EVENT1("category", "name",
+//                  "arg1", std::string("string will be copied"));
+//
+//
+// Convertable notes:
+// Converting a large data type to a string can be costly. To help with this,
+// the trace framework provides an interface ConvertableToTraceFormat. If you
+// inherit from it and implement the AppendAsTraceFormat method the trace
+// framework will call back to your object to convert a trace output time. This
+// means, if the category for the event is disabled, the conversion will not
+// happen.
+//
+//   class MyData : public base::trace_event::ConvertableToTraceFormat {
+//    public:
+//     MyData() {}
+//     void AppendAsTraceFormat(std::string* out) const override {
+//       out->append("{\"foo\":1}");
+//     }
+//    private:
+//     ~MyData() override {}
+//     DISALLOW_COPY_AND_ASSIGN(MyData);
+//   };
+//
+//   TRACE_EVENT1("foo", "bar", "data",
+//                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.
+
+#if defined(TRACE_EVENT0)
+#error "Another copy of this file has already been included."
+#endif
+
+// This will mark the trace event as disabled by default. The user will need
+// to explicitly enable the event.
+#define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name
+
+// Records a pair of begin and end events called "name" for the current
+// scope, with 0, 1 or 2 associated arguments. If the category is not
+// enabled, then this does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT0(category_group, name)    \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name)
+#define TRACE_EVENT_WITH_FLOW0(category_group, name, bind_id, flow_flags)  \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
+                                            flow_flags)
+#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val)
+#define TRACE_EVENT_WITH_FLOW1(category_group, name, bind_id, flow_flags,  \
+                               arg1_name, arg1_val)                        \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
+                                            flow_flags, arg1_name, arg1_val)
+#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name,   \
+                     arg2_val)                                               \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val, \
+                                  arg2_name, arg2_val)
+#define TRACE_EVENT_WITH_FLOW2(category_group, name, bind_id, flow_flags,    \
+                               arg1_name, arg1_val, arg2_name, arg2_val)     \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id,   \
+                                            flow_flags, arg1_name, arg1_val, \
+                                            arg2_name, arg2_val)
+
+// UNSHIPPED_TRACE_EVENT* are like TRACE_EVENT* except that they are not
+// included in official builds.
+
+#if OFFICIAL_BUILD
+#undef TRACING_IS_OFFICIAL_BUILD
+#define TRACING_IS_OFFICIAL_BUILD 1
+#elif !defined(TRACING_IS_OFFICIAL_BUILD)
+#define TRACING_IS_OFFICIAL_BUILD 0
+#endif
+
+#if TRACING_IS_OFFICIAL_BUILD
+#define UNSHIPPED_TRACE_EVENT0(category_group, name) (void)0
+#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+  (void)0
+#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \
+                               arg2_name, arg2_val)                       \
+  (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, \
+                                       arg1_val)                               \
+  (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, \
+                                       arg1_val, arg2_name, arg2_val)          \
+  (void)0
+#else
+#define UNSHIPPED_TRACE_EVENT0(category_group, name) \
+  TRACE_EVENT0(category_group, name)
+#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+  TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \
+                               arg2_name, arg2_val)                       \
+  TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) \
+  TRACE_EVENT_INSTANT0(category_group, name, scope)
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, \
+                                       arg1_val)                               \
+  TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, \
+                                       arg1_val, arg2_name, arg2_val)          \
+  TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val,       \
+                       arg2_name, arg2_val)
+#endif
+
+// Records a single event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT_INSTANT0(category_group, name, scope)                   \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE | scope)
+#define TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name,    \
+                           TRACE_EVENT_FLAG_NONE | scope, arg1_name, arg1_val)
+#define TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \
+                             arg2_name, arg2_val)                              \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name,    \
+                           TRACE_EVENT_FLAG_NONE | scope, arg1_name, arg1_val, \
+                           arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_INSTANT0(category_group, name, scope)              \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY | scope)
+#define TRACE_EVENT_COPY_INSTANT1(category_group, name, scope, arg1_name,   \
+                                  arg1_val)                                 \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY | scope, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_INSTANT2(category_group, name, scope, arg1_name,      \
+                                  arg1_val, arg2_name, arg2_val)               \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name,    \
+                           TRACE_EVENT_FLAG_COPY | scope, arg1_name, arg1_val, \
+                           arg2_name, arg2_val)
+
+#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope, \
+                                            timestamp)                   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                    \
+      TRACE_EVENT_PHASE_INSTANT, category_group, name, 0, 0, timestamp,  \
+      TRACE_EVENT_FLAG_NONE | scope)
+
+// Syntactic sugars for the sampling tracing in the main thread.
+#define TRACE_EVENT_SCOPED_SAMPLING_STATE(category, name) \
+  TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(0, category, name)
+#define TRACE_EVENT_GET_SAMPLING_STATE() \
+  TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(0)
+#define TRACE_EVENT_SET_SAMPLING_STATE(category, name) \
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(0, category, name)
+#define TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(categoryAndName) \
+  TRACE_EVENT_SET_NONCONST_SAMPLING_STATE_FOR_BUCKET(0, categoryAndName)
+
+// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT_BEGIN0(category_group, name)                          \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_BEGIN1(category_group, name, arg1_name, arg1_val)     \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_BEGIN2(category_group, name, arg1_name, arg1_val,     \
+                           arg2_name, arg2_val)                           \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val,    \
+                           arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_BEGIN0(category_group, name)                     \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN1(category_group, name, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name,  \
+                           TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN2(category_group, name, arg1_name, arg1_val, \
+                                arg2_name, arg2_val)                       \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name,  \
+                           TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val,     \
+                           arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_BEGINx but with a custom |at| timestamp provided.
+// - |id| is used to match the _BEGIN event with the _END event.
+//   Events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+#define TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category_group, name, id, \
+                                                     thread_id, timestamp)     \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id,      \
+      timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(                \
+    category_group, name, id, thread_id, timestamp)                       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+      timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1(                \
+    category_group, name, id, thread_id, timestamp, arg1_name, arg1_val)  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+      timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2(                \
+    category_group, name, id, thread_id, timestamp, arg1_name, arg1_val,  \
+    arg2_name, arg2_val)                                                  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+      timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name,   \
+      arg2_val)
+
+// Records a single END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT_END0(category_group, name)                          \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_END1(category_group, name, arg1_name, arg1_val)     \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_END2(category_group, name, arg1_name, arg1_val, arg2_name, \
+                         arg2_val)                                             \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name,        \
+                           TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val,         \
+                           arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_END0(category_group, name)                     \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END1(category_group, name, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name,  \
+                           TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END2(category_group, name, arg1_name, arg1_val, \
+                              arg2_name, arg2_val)                       \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name,  \
+                           TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val,   \
+                           arg2_name, arg2_val)
+
+#define TRACE_EVENT_MARK_WITH_TIMESTAMP1(category_group, name, timestamp, \
+                                         arg1_name, arg1_val)             \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp,      \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+
+#define TRACE_EVENT_COPY_MARK(category_group, name)                      \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_MARK, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY)
+
+#define TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(category_group, name, timestamp) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp,          \
+      TRACE_EVENT_FLAG_COPY)
+
+// Similar to TRACE_EVENT_ENDx but with a custom |at| timestamp provided.
+// - |id| is used to match the _BEGIN event with the _END event.
+//   Events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+#define TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(category_group, name, id, \
+                                                   thread_id, timestamp)     \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                        \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id,      \
+      timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0(                \
+    category_group, name, id, thread_id, timestamp)                     \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                   \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+      timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1(                 \
+    category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                    \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id,  \
+      timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2(                 \
+    category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+    arg2_name, arg2_val)                                                 \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                    \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id,  \
+      timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name,  \
+      arg2_val)
+
+// Records the value of a counter called "name" immediately. Value
+// must be representable as a 32 bit integer.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_COUNTER1(category_group, name, value)                         \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, "value",                  \
+                           static_cast<int>(value))
+#define TRACE_COPY_COUNTER1(category_group, name, value)                    \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY, "value",                  \
+                           static_cast<int>(value))
+
+// Records the values of a multi-parted counter called "name" immediately.
+// The UI will treat value1 and value2 as parts of a whole, displaying their
+// values as a stacked-bar chart.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_COUNTER2(category_group, name, value1_name, value1_val,       \
+                       value2_name, value2_val)                             \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, value1_name,              \
+                           static_cast<int>(value1_val), value2_name,       \
+                           static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER2(category_group, name, value1_name, value1_val,  \
+                            value2_name, value2_val)                        \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY, value1_name,              \
+                           static_cast<int>(value1_val), value2_name,       \
+                           static_cast<int>(value2_val))
+
+// Similar to TRACE_COUNTERx, but with a custom |timestamp| provided.
+#define TRACE_COUNTER_WITH_TIMESTAMP1(category_group, name, timestamp, value) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                    \
+      TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp,             \
+      TRACE_EVENT_FLAG_NONE, "value", static_cast<int>(value))
+
+#define TRACE_COUNTER_WITH_TIMESTAMP2(category_group, name, timestamp,      \
+                                      value1_name, value1_val, value2_name, \
+                                      value2_val)                           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                  \
+      TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp,           \
+      TRACE_EVENT_FLAG_NONE, value1_name, static_cast<int>(value1_val),     \
+      value2_name, static_cast<int>(value2_val))
+
+// Records the value of a counter called "name" immediately. Value
+// must be representable as a 32 bit integer.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to disambiguate counters with the same name. It must either
+//   be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
+//   will be xored with a hash of the process ID so that the same pointer on
+//   two different processes will not collide.
+#define TRACE_COUNTER_ID1(category_group, name, id, value)                    \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE, "value",  \
+                                   static_cast<int>(value))
+#define TRACE_COPY_COUNTER_ID1(category_group, name, id, value)               \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY, "value",  \
+                                   static_cast<int>(value))
+
+// Records the values of a multi-parted counter called "name" immediately.
+// The UI will treat value1 and value2 as parts of a whole, displaying their
+// values as a stacked-bar chart.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to disambiguate counters with the same name. It must either
+//   be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
+//   will be xored with a hash of the process ID so that the same pointer on
+//   two different processes will not collide.
+#define TRACE_COUNTER_ID2(category_group, name, id, value1_name, value1_val,  \
+                          value2_name, value2_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE,           \
+                                   value1_name, static_cast<int>(value1_val), \
+                                   value2_name, static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER_ID2(category_group, name, id, value1_name,         \
+                               value1_val, value2_name, value2_val)           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY,           \
+                                   value1_name, static_cast<int>(value1_val), \
+                                   value2_name, static_cast<int>(value2_val))
+
+// TRACE_EVENT_SAMPLE_* events are injected by the sampling profiler.
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP0(category_group, name,       \
+                                                   thread_id, timestamp)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+      TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1(                            \
+    category_group, name, thread_id, timestamp, arg1_name, arg1_val)           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP2(category_group, name,       \
+                                                   thread_id, timestamp,       \
+                                                   arg1_name, arg1_val,        \
+                                                   arg2_name, arg2_val)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// ASYNC_STEP_* APIs should be only used by legacy code. New code should
+// consider using NESTABLE_ASYNC_* APIs to describe substeps within an async
+// event.
+// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC
+//   events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+//
+// An asynchronous operation can consist of multiple phases. The first phase is
+// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the
+// ASYNC_STEP_INTO or ASYNC_STEP_PAST macros. The ASYNC_STEP_INTO macro will
+// annotate the block following the call. The ASYNC_STEP_PAST macro will
+// annotate the block prior to the call. Note that any particular event must use
+// only STEP_INTO or STEP_PAST macros; they can not mix and match. When the
+// operation completes, call ASYNC_END.
+//
+// An ASYNC trace typically occurs on a single thread (if not, they will only be
+// drawn on the thread defined in the ASYNC_BEGIN event), but all events in that
+// operation must use the same |name| and |id|. Each step can have its own
+// args.
+#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+                                   category_group, name, id,      \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+                                 arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN,     \
+                                   category_group, name, id,          \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+                                 arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                   \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,        \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category_group, name, id)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+                                   category_group, name, id,      \
+                                   TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+                                      arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN,          \
+                                   category_group, name, id,               \
+                                   TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+                                      arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                        \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,             \
+      TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_ASYNC_BEGINx but with a custom |at| timestamp
+// provided.
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \
+                                                timestamp)                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,            \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1(                           \
+    category_group, name, id, timestamp, arg1_name, arg1_val)              \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                      \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,             \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+      arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \
+                                                     timestamp)                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,                 \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+
+// Records a single ASYNC_STEP_INTO event for |step| immediately. If the
+// category is not enabled, then this does nothing. The |name| and |id| must
+// match the ASYNC_BEGIN event above. The |step| param identifies this step
+// within the async event. This should be called at the beginning of the next
+// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_PAST events.
+#define TRACE_EVENT_ASYNC_STEP_INTO0(category_group, name, id, step)  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
+                                   category_group, name, id,          \
+                                   TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_INTO1(category_group, name, id, step, \
+                                     arg1_name, arg1_val)            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                  \
+      TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id,   \
+      TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val)
+
+// Similar to TRACE_EVENT_ASYNC_STEP_INTOx but with a custom |at| timestamp
+// provided.
+#define TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category_group, name, id, \
+                                                    step, timestamp)          \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id,            \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE,    \
+      "step", step)
+
+// Records a single ASYNC_STEP_PAST event for |step| immediately. If the
+// category is not enabled, then this does nothing. The |name| and |id| must
+// match the ASYNC_BEGIN event above. The |step| param identifies this step
+// within the async event. This should be called at the beginning of the next
+// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_INTO events.
+#define TRACE_EVENT_ASYNC_STEP_PAST0(category_group, name, id, step)  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
+                                   category_group, name, id,          \
+                                   TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_PAST1(category_group, name, id, step, \
+                                     arg1_name, arg1_val)            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                  \
+      TRACE_EVENT_PHASE_ASYNC_STEP_PAST, category_group, name, id,   \
+      TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val)
+
+// Records a single ASYNC_END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+#define TRACE_EVENT_ASYNC_END0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+                                   category_group, name, id,    \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END,               \
+                                   category_group, name, id,                  \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_END2(category_group, name, id, arg1_name, arg1_val, \
+                               arg2_name, arg2_val)                           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                           \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                  \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_END0(category_group, name, id)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+                                   category_group, name, id,    \
+                                   TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_END1(category_group, name, id, arg1_name, \
+                                    arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END,          \
+                                   category_group, name, id,             \
+                                   TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_END2(category_group, name, id, arg1_name, \
+                                    arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                      \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,             \
+      TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_ASYNC_ENDx but with a custom |at| timestamp provided.
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(category_group, name, id, \
+                                              timestamp)                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                   \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,            \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP1(category_group, name, id,       \
+                                              timestamp, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                  \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE,    \
+      arg1_name, arg1_val)
+
+// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
+// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
+// events.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - A pair of NESTABLE_ASYNC_BEGIN event and NESTABLE_ASYNC_END event is
+//   considered as a match if their category_group, name and id all match.
+// - |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+// - |id| is used to match a child NESTABLE_ASYNC event with its parent
+//   NESTABLE_ASYNC event. Therefore, events in the same nested event tree must
+//   be logged using the same id and category_group.
+//
+// Unmatched NESTABLE_ASYNC_END event will be parsed as an event that starts
+// at the first NESTABLE_ASYNC event of that id, and unmatched
+// NESTABLE_ASYNC_BEGIN event will be parsed as an event that ends at the last
+// NESTABLE_ASYNC event of that id. Corresponding warning messages for
+// unmatched events will be shown in the analysis view.
+
+// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with
+// 0, 1 or 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+                                   category_group, name, id,               \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+                                          arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN,     \
+                                   category_group, name, id,                   \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+                                          arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id,        \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 0
+// or 2 associated arguments. If the category is not enabled, then this does
+// nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_END0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+                                   category_group, name, id,             \
+                                   TRACE_EVENT_FLAG_NONE)
+// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 1
+// associated argument. If the category is not enabled, then this does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_END1(category_group, name, id, arg1_name, \
+                                        arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END,     \
+                                   category_group, name, id,                 \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
+                                        arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                          \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id,        \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with one associated argument. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(category_group, name, id,        \
+                                            arg1_name, arg1_val)             \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \
+                                   category_group, name, id,                 \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2(                              \
+    category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                       \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, category_group, name, id, \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(                       \
+    category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id,        \
+      TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+      arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(                         \
+    category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id,          \
+      TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+      arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_NESTABLE_ASYNC_{BEGIN,END}x but with a custom
+// |timestamp| provided.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, \
+                                                         id, timestamp)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id,        \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(category_group, name, \
+                                                       id, timestamp)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                        \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id,        \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(          \
+    category_group, name, id, timestamp)                                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                   \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(          \
+    category_group, name, id, timestamp)                              \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                 \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2(                              \
+    category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                       \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, category_group, name, id, \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW
+//   events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+// FLOW events are different from ASYNC events in how they are drawn by the
+// tracing UI. A FLOW defines asynchronous data flow, such as posting a task
+// (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be
+// drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar
+// to ASYNC, a FLOW can consist of multiple phases. The first phase is defined
+// by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP
+// macros. When the operation completes, call FLOW_END. An async operation can
+// span threads and processes, but all events in that operation must use the
+// same |name| and |id|. Each event can have its own args.
+#define TRACE_EVENT_FLOW_BEGIN0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+                                   category_group, name, id,     \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_BEGIN1(category_group, name, id, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN,               \
+                                   category_group, name, id,                   \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_BEGIN2(category_group, name, id, arg1_name, arg1_val, \
+                                arg2_name, arg2_val)                           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_FLOW_BEGIN, category_group, name, id,                  \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN0(category_group, name, id)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+                                   category_group, name, id,     \
+                                   TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_BEGIN1(category_group, name, id, arg1_name, \
+                                     arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN,          \
+                                   category_group, name, id,              \
+                                   TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN2(category_group, name, id, arg1_name, \
+                                     arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                       \
+      TRACE_EVENT_PHASE_FLOW_BEGIN, category_group, name, id,             \
+      TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single FLOW_STEP event for |step| immediately. If the category
+// is not enabled, then this does nothing. The |name| and |id| must match the
+// FLOW_BEGIN event above. The |step| param identifies this step within the
+// async event. This should be called at the beginning of the next phase of an
+// asynchronous operation.
+#define TRACE_EVENT_FLOW_STEP0(category_group, name, id, step)  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+                                   category_group, name, id,    \
+                                   TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_FLOW_STEP1(category_group, name, id, step, arg1_name, \
+                               arg1_val)                                  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                       \
+      TRACE_EVENT_PHASE_FLOW_STEP, category_group, name, id,              \
+      TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_STEP0(category_group, name, id, step) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP,     \
+                                   category_group, name, id,        \
+                                   TRACE_EVENT_FLAG_COPY, "step", step)
+#define TRACE_EVENT_COPY_FLOW_STEP1(category_group, name, id, step, arg1_name, \
+                                    arg1_val)                                  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_FLOW_STEP, category_group, name, id,                   \
+      TRACE_EVENT_FLAG_COPY, "step", step, arg1_name, arg1_val)
+
+// Records a single FLOW_END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+#define TRACE_EVENT_FLOW_END0(category_group, name, id)                        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0(category_group, name, id)      \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id,                                   \
+                                   TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
+#define TRACE_EVENT_FLOW_END1(category_group, name, id, arg1_name, arg1_val)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \
+                                   arg1_val)
+#define TRACE_EVENT_FLOW_END2(category_group, name, id, arg1_name, arg1_val,   \
+                              arg2_name, arg2_val)                             \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \
+                                   arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_END0(category_group, name, id)                   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_END1(category_group, name, id, arg1_name,        \
+                                   arg1_val)                                   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \
+                                   arg1_val)
+#define TRACE_EVENT_COPY_FLOW_END2(category_group, name, id, arg1_name,        \
+                                   arg1_val, arg2_name, arg2_val)              \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \
+                                   arg1_val, arg2_name, arg2_val)
+
+// Macros to track the life time and value of arbitrary client objects.
+// See also TraceTrackableObject.
+#define TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group, name, id) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                  \
+      TRACE_EVENT_PHASE_CREATE_OBJECT, category_group, name,         \
+      TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group, name, id, \
+                                            snapshot)                 \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                   \
+      TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name,        \
+      TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE, "snapshot", snapshot)
+
+#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP(                    \
+    category_group, name, id, timestamp, snapshot)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name,                \
+      TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, \
+      TRACE_EVENT_FLAG_NONE, "snapshot", snapshot)
+
+#define TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group, name, id) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                  \
+      TRACE_EVENT_PHASE_DELETE_OBJECT, category_group, name,         \
+      TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
+
+// Macro to efficiently determine if a given category group is enabled.
+#define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret)             \
+  do {                                                                      \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                 \
+    if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+      *ret = true;                                                          \
+    } else {                                                                \
+      *ret = false;                                                         \
+    }                                                                       \
+  } while (0)
+
+// Macro to explicitly warm up a given category group. This could be useful in
+// cases where we want to initialize a category group before any trace events
+// for that category group is reported. For example, to have a category group
+// always show up in the "record categories" list for manually selecting
+// settings in about://tracing.
+#define TRACE_EVENT_WARMUP_CATEGORY(category_group) \
+  INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group)
+
+// Macro to efficiently determine, through polling, if a new trace has begun.
+#define TRACE_EVENT_IS_NEW_TRACE(ret)                                      \
+  do {                                                                     \
+    static int INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = 0;          \
+    int num_traces_recorded = TRACE_EVENT_API_GET_NUM_TRACES_RECORDED();   \
+    if (num_traces_recorded != -1 &&                                       \
+        num_traces_recorded !=                                             \
+            INTERNAL_TRACE_EVENT_UID(lastRecordingNumber)) {               \
+      INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = num_traces_recorded; \
+      *ret = true;                                                         \
+    } else {                                                               \
+      *ret = false;                                                        \
+    }                                                                      \
+  } while (0)
+
+// Notes regarding the following definitions:
+// New values can be added and propagated to third party libraries, but existing
+// definitions must never be changed, because third party libraries may use old
+// definitions.
+
+// Phase indicates the nature of an event entry. E.g. part of a begin/end pair.
+#define TRACE_EVENT_PHASE_BEGIN ('B')
+#define TRACE_EVENT_PHASE_END ('E')
+#define TRACE_EVENT_PHASE_COMPLETE ('X')
+#define TRACE_EVENT_PHASE_INSTANT ('I')
+#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_INTO ('T')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_PAST ('p')
+#define TRACE_EVENT_PHASE_ASYNC_END ('F')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN ('b')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_END ('e')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT ('n')
+#define TRACE_EVENT_PHASE_FLOW_BEGIN ('s')
+#define TRACE_EVENT_PHASE_FLOW_STEP ('t')
+#define TRACE_EVENT_PHASE_FLOW_END ('f')
+#define TRACE_EVENT_PHASE_METADATA ('M')
+#define TRACE_EVENT_PHASE_COUNTER ('C')
+#define TRACE_EVENT_PHASE_SAMPLE ('P')
+#define TRACE_EVENT_PHASE_CREATE_OBJECT ('N')
+#define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O')
+#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D')
+#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v')
+#define TRACE_EVENT_PHASE_MARK ('R')
+
+// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
+#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned int>(0))
+#define TRACE_EVENT_FLAG_COPY (static_cast<unsigned int>(1 << 0))
+#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned int>(1 << 1))
+#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned int>(1 << 2))
+#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned int>(1 << 3))
+#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast<unsigned int>(1 << 4))
+#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned int>(1 << 5))
+#define TRACE_EVENT_FLAG_ASYNC_TTS (static_cast<unsigned int>(1 << 6))
+#define TRACE_EVENT_FLAG_BIND_TO_ENCLOSING (static_cast<unsigned int>(1 << 7))
+#define TRACE_EVENT_FLAG_FLOW_IN (static_cast<unsigned int>(1 << 8))
+#define TRACE_EVENT_FLAG_FLOW_OUT (static_cast<unsigned int>(1 << 9))
+#define TRACE_EVENT_FLAG_HAS_CONTEXT_ID (static_cast<unsigned int>(1 << 10))
+#define TRACE_EVENT_FLAG_HAS_PROCESS_ID (static_cast<unsigned int>(1 << 11))
+
+#define TRACE_EVENT_FLAG_SCOPE_MASK                          \
+  (static_cast<unsigned int>(TRACE_EVENT_FLAG_SCOPE_OFFSET | \
+                             TRACE_EVENT_FLAG_SCOPE_EXTRA))
+
+// Type values for identifying types in the TraceValue union.
+#define TRACE_VALUE_TYPE_BOOL (static_cast<unsigned char>(1))
+#define TRACE_VALUE_TYPE_UINT (static_cast<unsigned char>(2))
+#define TRACE_VALUE_TYPE_INT (static_cast<unsigned char>(3))
+#define TRACE_VALUE_TYPE_DOUBLE (static_cast<unsigned char>(4))
+#define TRACE_VALUE_TYPE_POINTER (static_cast<unsigned char>(5))
+#define TRACE_VALUE_TYPE_STRING (static_cast<unsigned char>(6))
+#define TRACE_VALUE_TYPE_COPY_STRING (static_cast<unsigned char>(7))
+#define TRACE_VALUE_TYPE_CONVERTABLE (static_cast<unsigned char>(8))
+
+// Enum reflecting the scope of an INSTANT event. Must fit within
+// TRACE_EVENT_FLAG_SCOPE_MASK.
+#define TRACE_EVENT_SCOPE_GLOBAL (static_cast<unsigned char>(0 << 3))
+#define TRACE_EVENT_SCOPE_PROCESS (static_cast<unsigned char>(1 << 3))
+#define TRACE_EVENT_SCOPE_THREAD (static_cast<unsigned char>(2 << 3))
+
+#define TRACE_EVENT_SCOPE_NAME_GLOBAL ('g')
+#define TRACE_EVENT_SCOPE_NAME_PROCESS ('p')
+#define TRACE_EVENT_SCOPE_NAME_THREAD ('t')
diff --git a/base/trace_event/etw_manifest/BUILD.gn b/base/trace_event/etw_manifest/BUILD.gn
index f62e356..ed83aab 100644
--- a/base/trace_event/etw_manifest/BUILD.gn
+++ b/base/trace_event/etw_manifest/BUILD.gn
@@ -2,47 +2,19 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/win/message_compiler.gni")
+
 assert(is_win, "This only runs on Windows.")
 
-# 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") {
+message_compiler("chrome_events_win") {
   visibility = [
     "//base/trace_event/*",
     "//chrome:main_dll",
   ]
 
-  sources = get_target_outputs(":chrome_events_win_generate")
-
-  deps = [
-    ":chrome_events_win_generate",
+  sources = [
+    "chrome_events_win.man",
   ]
+
+  user_mode_logging = true
 }
diff --git a/base/trace_event/etw_manifest/BUILD/message_compiler.py b/base/trace_event/etw_manifest/BUILD/message_compiler.py
deleted file mode 100644
index be5927d..0000000
--- a/base/trace_event/etw_manifest/BUILD/message_compiler.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2015 The Chromium 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/heap_profiler_allocation_context.cc b/base/trace_event/heap_profiler_allocation_context.cc
new file mode 100644
index 0000000..038c083
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context.cc
@@ -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.
+
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+#include <cstring>
+
+#include "base/hash.h"
+#include "base/macros.h"
+
+namespace base {
+namespace trace_event {
+
+// Constructor that does not initialize members.
+AllocationContext::AllocationContext() {}
+
+// static
+AllocationContext AllocationContext::Empty() {
+  AllocationContext ctx;
+
+  for (size_t i = 0; i < arraysize(ctx.backtrace.frames); i++)
+    ctx.backtrace.frames[i] = nullptr;
+
+  ctx.type_name = nullptr;
+
+  return ctx;
+}
+
+bool operator==(const Backtrace& lhs, const Backtrace& rhs) {
+  // Pointer equality of the stack frames is assumed, so instead of doing a deep
+  // string comparison on all of the frames, a |memcmp| suffices.
+  return std::memcmp(lhs.frames, rhs.frames, sizeof(lhs.frames)) == 0;
+}
+
+bool operator==(const AllocationContext& lhs, const AllocationContext& rhs) {
+  return (lhs.backtrace == rhs.backtrace) && (lhs.type_name == rhs.type_name);
+}
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+using base::trace_event::AllocationContext;
+using base::trace_event::Backtrace;
+
+size_t hash<Backtrace>::operator()(const Backtrace& backtrace) const {
+  return base::SuperFastHash(reinterpret_cast<const char*>(backtrace.frames),
+                             sizeof(backtrace.frames));
+}
+
+size_t hash<AllocationContext>::operator()(const AllocationContext& ctx) const {
+  size_t backtrace_hash = hash<Backtrace>()(ctx.backtrace);
+
+  // Multiplicative hash from [Knuth 1998]. Works best if |size_t| is 32 bits,
+  // because the magic number is a prime very close to 2^32 / golden ratio, but
+  // will still redistribute keys bijectively on 64-bit architectures because
+  // the magic number is coprime to 2^64.
+  size_t type_hash = reinterpret_cast<size_t>(ctx.type_name) * 2654435761;
+
+  // Multiply one side to break the commutativity of +. Multiplication with a
+  // number coprime to |numeric_limits<size_t>::max() + 1| is bijective so
+  // randomness is preserved.
+  return (backtrace_hash * 3) + type_hash;
+}
+
+}  // BASE_HASH_NAMESPACE
diff --git a/base/trace_event/heap_profiler_allocation_context.h b/base/trace_event/heap_profiler_allocation_context.h
new file mode 100644
index 0000000..6a46d03
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context.h
@@ -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.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+
+namespace base {
+namespace trace_event {
+
+// When heap profiling is enabled, tracing keeps track of the allocation
+// context for each allocation intercepted. It is generated by the
+// |AllocationContextTracker| which keeps stacks of context in TLS.
+// The tracker is initialized lazily.
+
+// The backtrace in the allocation context is a snapshot of the stack. For now,
+// this is the pseudo stack where frames are created by trace event macros. In
+// the future, we might add the option to use the native call stack. In that
+// case, |Backtrace| and |AllocationContextTracker::GetContextSnapshot| might
+// have different implementations that can be selected by a compile time flag.
+
+// The number of stack frames stored in the backtrace is a trade off between
+// memory used for tracing and accuracy. Measurements done on a prototype
+// revealed that:
+//
+// - In 60 percent of the cases, stack depth <= 7.
+// - In 87 percent of the cases, stack depth <= 9.
+// - In 95 percent of the cases, stack depth <= 11.
+//
+// See the design doc (https://goo.gl/4s7v7b) for more details.
+
+using StackFrame = const char*;
+
+struct BASE_EXPORT Backtrace {
+  // Unused backtrace frames are filled with nullptr frames. If the stack is
+  // higher than what can be stored here, the bottom frames are stored. Based
+  // on the data above, a depth of 12 captures the full stack in the vast
+  // majority of the cases.
+  StackFrame frames[12];
+};
+
+bool BASE_EXPORT operator==(const Backtrace& lhs, const Backtrace& rhs);
+
+// The |AllocationContext| is context metadata that is kept for every allocation
+// when heap profiling is enabled. To simplify memory management for book-
+// keeping, this struct has a fixed size. All |const char*|s here must have
+// static lifetime.
+struct BASE_EXPORT AllocationContext {
+ public:
+  // An allocation context with empty backtrace and unknown type.
+  static AllocationContext Empty();
+
+  Backtrace backtrace;
+
+  // Type name of the type stored in the allocated memory. A null pointer
+  // indicates "unknown type". Grouping is done by comparing pointers, not by
+  // deep string comparison. In a component build, where a type name can have a
+  // string literal in several dynamic libraries, this may distort grouping.
+  const char* type_name;
+
+ private:
+  friend class AllocationContextTracker;
+
+  // Don't allow uninitialized instances except inside the allocation context
+  // tracker. Except in tests, an |AllocationContext| should only be obtained
+  // from the tracker. In tests, paying the overhead of initializing the struct
+  // to |Empty| and then overwriting the members is not such a big deal.
+  AllocationContext();
+};
+
+bool BASE_EXPORT operator==(const AllocationContext& lhs,
+                            const AllocationContext& rhs);
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+
+template <>
+struct hash<base::trace_event::Backtrace> {
+  size_t operator()(const base::trace_event::Backtrace& backtrace) const;
+};
+
+template <>
+struct hash<base::trace_event::AllocationContext> {
+  size_t operator()(const base::trace_event::AllocationContext& context) const;
+};
+
+}  // BASE_HASH_NAMESPACE
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc
new file mode 100644
index 0000000..791ab7a
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -0,0 +1,115 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "base/atomicops.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0;
+
+namespace {
+
+ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER;
+
+// This function is added to the TLS slot to clean up the instance when the
+// thread exits.
+void DestructAllocationContextTracker(void* alloc_ctx_tracker) {
+  delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker);
+}
+
+}  // namespace
+
+AllocationContextTracker::AllocationContextTracker() {}
+AllocationContextTracker::~AllocationContextTracker() {}
+
+// static
+AllocationContextTracker* AllocationContextTracker::GetThreadLocalTracker() {
+  auto tracker =
+      static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get());
+
+  if (!tracker) {
+    tracker = new AllocationContextTracker();
+    g_tls_alloc_ctx_tracker.Set(tracker);
+  }
+
+  return tracker;
+}
+
+// static
+void AllocationContextTracker::SetCaptureEnabled(bool enabled) {
+  // When enabling capturing, also initialize the TLS slot. This does not create
+  // a TLS instance yet.
+  if (enabled && !g_tls_alloc_ctx_tracker.initialized())
+    g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker);
+
+  // Release ordering ensures that when a thread observes |capture_enabled_| to
+  // be true through an acquire load, the TLS slot has been initialized.
+  subtle::Release_Store(&capture_enabled_, enabled);
+}
+
+// static
+void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) {
+  auto tracker = AllocationContextTracker::GetThreadLocalTracker();
+
+  // Impose a limit on the height to verify that every push is popped, because
+  // in practice the pseudo stack never grows higher than ~20 frames.
+  DCHECK_LT(tracker->pseudo_stack_.size(), 128u);
+  tracker->pseudo_stack_.push_back(frame);
+}
+
+// static
+void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) {
+  auto tracker = AllocationContextTracker::GetThreadLocalTracker();
+
+  // Guard for stack underflow. If tracing was started with a TRACE_EVENT in
+  // scope, the frame was never pushed, so it is possible that pop is called
+  // on an empty stack.
+  if (tracker->pseudo_stack_.empty())
+    return;
+
+  // Assert that pushes and pops are nested correctly. This DCHECK can be
+  // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call
+  // without a corresponding TRACE_EVENT_BEGIN).
+  DCHECK_EQ(frame, tracker->pseudo_stack_.back())
+      << "Encountered an unmatched TRACE_EVENT_END";
+
+  tracker->pseudo_stack_.pop_back();
+}
+
+// static
+AllocationContext AllocationContextTracker::GetContextSnapshot() {
+  AllocationContextTracker* tracker = GetThreadLocalTracker();
+  AllocationContext ctx;
+
+  // Fill the backtrace.
+  {
+    auto src = tracker->pseudo_stack_.begin();
+    auto dst = std::begin(ctx.backtrace.frames);
+    auto src_end = tracker->pseudo_stack_.end();
+    auto dst_end = std::end(ctx.backtrace.frames);
+
+    // Copy as much of the bottom of the pseudo stack into the backtrace as
+    // possible.
+    for (; src != src_end && dst != dst_end; src++, dst++)
+      *dst = *src;
+
+    // If there is room for more, fill the remaining slots with empty frames.
+    std::fill(dst, dst_end, nullptr);
+  }
+
+  ctx.type_name = nullptr;
+
+  return ctx;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.h b/base/trace_event/heap_profiler_allocation_context_tracker.h
new file mode 100644
index 0000000..9c9a313
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.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 BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+// The allocation context tracker keeps track of thread-local context for heap
+// profiling. It includes a pseudo stack of trace events. On every allocation
+// the tracker provides a snapshot of its context in the form of an
+// |AllocationContext| that is to be stored together with the allocation
+// details.
+class BASE_EXPORT AllocationContextTracker {
+ public:
+  // Globally enables capturing allocation context.
+  // TODO(ruuda): Should this be replaced by |EnableCapturing| in the future?
+  // Or at least have something that guards agains enable -> disable -> enable?
+  static void SetCaptureEnabled(bool enabled);
+
+  // Returns whether capturing allocation context is enabled globally.
+  inline static bool capture_enabled() {
+    // A little lag after heap profiling is enabled or disabled is fine, it is
+    // more important that the check is as cheap as possible when capturing is
+    // not enabled, so do not issue a memory barrier in the fast path.
+    if (subtle::NoBarrier_Load(&capture_enabled_) == 0)
+      return false;
+
+    // In the slow path, an acquire load is required to pair with the release
+    // store in |SetCaptureEnabled|. This is to ensure that the TLS slot for
+    // the thread-local allocation context tracker has been initialized if
+    // |capture_enabled| returns true.
+    return subtle::Acquire_Load(&capture_enabled_) != 0;
+  }
+
+  // Pushes a frame onto the thread-local pseudo stack.
+  static void PushPseudoStackFrame(StackFrame frame);
+
+  // Pops a frame from the thread-local pseudo stack.
+  static void PopPseudoStackFrame(StackFrame frame);
+
+  // Returns a snapshot of the current thread-local context.
+  static AllocationContext GetContextSnapshot();
+
+  ~AllocationContextTracker();
+
+ private:
+  AllocationContextTracker();
+
+  static AllocationContextTracker* GetThreadLocalTracker();
+
+  static subtle::Atomic32 capture_enabled_;
+
+  // The pseudo stack where frames are |TRACE_EVENT| names.
+  std::vector<StackFrame> pseudo_stack_;
+
+  DISALLOW_COPY_AND_ASSIGN(AllocationContextTracker);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
new file mode 100644
index 0000000..130a927
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
@@ -0,0 +1,223 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iterator>
+
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/trace_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the pseudo stack requires pointer equality,
+// and string interning is unreliable.
+const char kCupcake[] = "Cupcake";
+const char kDonut[] = "Donut";
+const char kEclair[] = "Eclair";
+const char kFroyo[] = "Froyo";
+const char kGingerbread[] = "Gingerbread";
+
+// Asserts that the fixed-size array |expected_backtrace| matches the backtrace
+// in |AllocationContextTracker::GetContextSnapshot|.
+template <size_t N>
+void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) {
+  AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+
+  auto actual = std::begin(ctx.backtrace.frames);
+  auto actual_bottom = std::end(ctx.backtrace.frames);
+  auto expected = std::begin(expected_backtrace);
+  auto expected_bottom = std::end(expected_backtrace);
+
+  // Note that this requires the pointers to be equal, this is not doing a deep
+  // string comparison.
+  for (; actual != actual_bottom && expected != expected_bottom;
+       actual++, expected++)
+    ASSERT_EQ(*expected, *actual);
+
+  // Ensure that the height of the stacks is the same.
+  ASSERT_EQ(actual, actual_bottom);
+  ASSERT_EQ(expected, expected_bottom);
+}
+
+void AssertBacktraceEmpty() {
+  AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+
+  for (StackFrame frame : ctx.backtrace.frames)
+    ASSERT_EQ(nullptr, frame);
+}
+
+class AllocationContextTrackerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    TraceConfig config("");
+    TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE);
+    AllocationContextTracker::SetCaptureEnabled(true);
+  }
+
+  void TearDown() override {
+    AllocationContextTracker::SetCaptureEnabled(false);
+    TraceLog::GetInstance()->SetDisabled();
+  }
+};
+
+// Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly.
+// Also check that |GetContextSnapshot| fills the backtrace with null pointers
+// when the pseudo stack height is less than the capacity.
+TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) {
+  StackFrame c = kCupcake;
+  StackFrame d = kDonut;
+  StackFrame e = kEclair;
+  StackFrame f = kFroyo;
+
+  AssertBacktraceEmpty();
+
+  {
+    TRACE_EVENT0("Testing", kCupcake);
+    StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    AssertBacktraceEquals(frame_c);
+
+    {
+      TRACE_EVENT0("Testing", kDonut);
+      StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      AssertBacktraceEquals(frame_cd);
+    }
+
+    AssertBacktraceEquals(frame_c);
+
+    {
+      TRACE_EVENT0("Testing", kEclair);
+      StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+      AssertBacktraceEquals(frame_ce);
+    }
+
+    AssertBacktraceEquals(frame_c);
+  }
+
+  AssertBacktraceEmpty();
+
+  {
+    TRACE_EVENT0("Testing", kFroyo);
+    StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    AssertBacktraceEquals(frame_f);
+  }
+
+  AssertBacktraceEmpty();
+}
+
+// Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and
+// |TRACE_EVENT_END| macros.
+TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) {
+  StackFrame c = kCupcake;
+  StackFrame d = kDonut;
+  StackFrame e = kEclair;
+  StackFrame f = kFroyo;
+
+  StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  AssertBacktraceEmpty();
+
+  TRACE_EVENT_BEGIN0("Testing", kCupcake);
+  AssertBacktraceEquals(frame_c);
+
+  TRACE_EVENT_BEGIN0("Testing", kDonut);
+  AssertBacktraceEquals(frame_cd);
+  TRACE_EVENT_END0("Testing", kDonut);
+
+  AssertBacktraceEquals(frame_c);
+
+  TRACE_EVENT_BEGIN0("Testing", kEclair);
+  AssertBacktraceEquals(frame_ce);
+  TRACE_EVENT_END0("Testing", kEclair);
+
+  AssertBacktraceEquals(frame_c);
+  TRACE_EVENT_END0("Testing", kCupcake);
+
+  AssertBacktraceEmpty();
+
+  TRACE_EVENT_BEGIN0("Testing", kFroyo);
+  AssertBacktraceEquals(frame_f);
+  TRACE_EVENT_END0("Testing", kFroyo);
+
+  AssertBacktraceEmpty();
+}
+
+TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) {
+  StackFrame c = kCupcake;
+  StackFrame d = kDonut;
+  StackFrame e = kEclair;
+  StackFrame f = kFroyo;
+
+  StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  StackFrame frame_e[] = {e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  StackFrame frame_ef[] = {e, f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  AssertBacktraceEmpty();
+
+  TRACE_EVENT_BEGIN0("Testing", kCupcake);
+  AssertBacktraceEquals(frame_c);
+
+  {
+    TRACE_EVENT0("Testing", kDonut);
+    AssertBacktraceEquals(frame_cd);
+  }
+
+  AssertBacktraceEquals(frame_c);
+  TRACE_EVENT_END0("Testing", kCupcake);
+  AssertBacktraceEmpty();
+
+  {
+    TRACE_EVENT0("Testing", kEclair);
+    AssertBacktraceEquals(frame_e);
+
+    TRACE_EVENT_BEGIN0("Testing", kFroyo);
+    AssertBacktraceEquals(frame_ef);
+    TRACE_EVENT_END0("Testing", kFroyo);
+    AssertBacktraceEquals(frame_e);
+  }
+
+  AssertBacktraceEmpty();
+}
+
+TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
+  // Push 12 events onto the pseudo stack.
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kDonut);
+  TRACE_EVENT0("Testing", kEclair);
+  TRACE_EVENT0("Testing", kFroyo);
+
+  {
+    TRACE_EVENT0("Testing", kGingerbread);
+    AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+
+    // The pseudo stack relies on pointer equality, not deep string comparisons.
+    ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]);
+    ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]);
+  }
+
+  {
+    AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+    ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]);
+    ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]);
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_register.cc b/base/trace_event/heap_profiler_allocation_register.cc
new file mode 100644
index 0000000..37647ee
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_register.cc
@@ -0,0 +1,182 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_allocation_register.h"
+
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+AllocationRegister::AllocationRegister()
+    // Reserve enough address space to store |kNumCells| entries if necessary,
+    // with a guard page after it to crash the program when attempting to store
+    // more entries.
+    : cells_(static_cast<Cell*>(AllocateVirtualMemory(kNumCells *
+                                                      sizeof(Cell)))),
+      buckets_(static_cast<CellIndex*>(
+          AllocateVirtualMemory(kNumBuckets * sizeof(CellIndex)))),
+
+      // The free list is empty. The first unused cell is cell 1, because index
+      // 0 is used as list terminator.
+      free_list_(0),
+      next_unused_cell_(1) {}
+
+AllocationRegister::~AllocationRegister() {
+  FreeVirtualMemory(buckets_, kNumBuckets * sizeof(CellIndex));
+  FreeVirtualMemory(cells_, kNumCells * sizeof(Cell));
+}
+
+void AllocationRegister::Insert(void* address,
+                                size_t size,
+                                AllocationContext context) {
+  DCHECK(address != nullptr);
+
+  CellIndex* idx_ptr = Lookup(address);
+
+  // If the index is 0, the address is not yet present, so insert it.
+  if (*idx_ptr == 0) {
+    *idx_ptr = GetFreeCell();
+
+    cells_[*idx_ptr].allocation.address = address;
+    cells_[*idx_ptr].next = 0;
+  }
+
+  cells_[*idx_ptr].allocation.size = size;
+  cells_[*idx_ptr].allocation.context = context;
+}
+
+void AllocationRegister::Remove(void* address) {
+  // Get a pointer to the index of the cell that stores |address|. The index can
+  // be an element of |buckets_| or the |next| member of a cell.
+  CellIndex* idx_ptr = Lookup(address);
+  CellIndex freed_idx = *idx_ptr;
+
+  // If the index is 0, the address was not there in the first place.
+  if (freed_idx == 0)
+    return;
+
+  // The cell at the index is now free, remove it from the linked list for
+  // |Hash(address)|.
+  Cell* freed_cell = &cells_[freed_idx];
+  *idx_ptr = freed_cell->next;
+
+  // Put the free cell at the front of the free list.
+  freed_cell->next = free_list_;
+  free_list_ = freed_idx;
+
+  // Reset the address, so that on iteration the free cell is ignored.
+  freed_cell->allocation.address = nullptr;
+}
+
+AllocationRegister::ConstIterator AllocationRegister::begin() const {
+  // Initialize the iterator's index to 0. Cell 0 never stores an entry.
+  ConstIterator iterator(*this, 0);
+  // Incrementing will advance the iterator to the first used cell.
+  ++iterator;
+  return iterator;
+}
+
+AllocationRegister::ConstIterator AllocationRegister::end() const {
+  // Cell |next_unused_cell_ - 1| is the last cell that could contain an entry,
+  // so index |next_unused_cell_| is an iterator past the last element, in line
+  // with the STL iterator conventions.
+  return ConstIterator(*this, next_unused_cell_);
+}
+
+AllocationRegister::ConstIterator::ConstIterator(
+    const AllocationRegister& alloc_register,
+    CellIndex index)
+    : register_(alloc_register), index_(index) {}
+
+void AllocationRegister::ConstIterator::operator++() {
+  // Find the next cell with a non-null address until all cells that could
+  // possibly be used have been iterated. A null address indicates a free cell.
+  do {
+    index_++;
+  } while (index_ < register_.next_unused_cell_ &&
+           register_.cells_[index_].allocation.address == nullptr);
+}
+
+bool AllocationRegister::ConstIterator::operator!=(
+    const ConstIterator& other) const {
+  return index_ != other.index_;
+}
+
+const AllocationRegister::Allocation& AllocationRegister::ConstIterator::
+operator*() const {
+  return register_.cells_[index_].allocation;
+}
+
+AllocationRegister::CellIndex* AllocationRegister::Lookup(void* address) {
+  // The list head is in |buckets_| at the hash offset.
+  CellIndex* idx_ptr = &buckets_[Hash(address)];
+
+  // Chase down the list until the cell that holds |address| is found,
+  // or until the list ends.
+  while (*idx_ptr != 0 && cells_[*idx_ptr].allocation.address != address)
+    idx_ptr = &cells_[*idx_ptr].next;
+
+  return idx_ptr;
+}
+
+AllocationRegister::CellIndex AllocationRegister::GetFreeCell() {
+  // First try to re-use a cell from the freelist.
+  if (free_list_) {
+    CellIndex idx = free_list_;
+    free_list_ = cells_[idx].next;
+    return idx;
+  }
+
+  // Otherwise pick the next cell that has not been touched before.
+  CellIndex idx = next_unused_cell_;
+  next_unused_cell_++;
+
+  // If the hash table has too little capacity (when too little address space
+  // was reserved for |cells_|), |next_unused_cell_| can be an index outside of
+  // the allocated storage. A guard page is allocated there to crash the
+  // program in that case. There are alternative solutions:
+  // - Deal with it, increase capacity by reallocating |cells_|.
+  // - Refuse to insert and let the caller deal with it.
+  // Because free cells are re-used before accessing fresh cells with a higher
+  // index, and because reserving address space without touching it is cheap,
+  // the simplest solution is to just allocate a humongous chunk of address
+  // space.
+
+  DCHECK_LT(next_unused_cell_, kNumCells + 1);
+
+  return idx;
+}
+
+// static
+uint32_t AllocationRegister::Hash(void* address) {
+  // The multiplicative hashing scheme from [Knuth 1998]. The value of |a| has
+  // been chosen carefully based on measurements with real-word data (addresses
+  // recorded from a Chrome trace run). It is the first prime after 2^17. For
+  // |shift|, 13, 14 and 15 yield good results. These values are tuned to 2^18
+  // buckets. Microbenchmarks show that this simple scheme outperforms fancy
+  // hashes like Murmur3 by 20 to 40 percent.
+  const uintptr_t key = reinterpret_cast<uintptr_t>(address);
+  const uintptr_t a = 131101;
+  const uintptr_t shift = 14;
+  const uintptr_t h = (key * a) >> shift;
+  return static_cast<uint32_t>(h) & kNumBucketsMask;
+}
+
+void AllocationRegister::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) const {
+  // Estimate memory overhead by counting all of the cells that have ever been
+  // touched. Don't report mmapped memory as allocated, because it has not been
+  // allocated by malloc.
+  size_t allocated = sizeof(AllocationRegister);
+  size_t resident = sizeof(AllocationRegister)
+                    // Include size of touched cells (size of |*cells_|).
+                    + sizeof(Cell) * next_unused_cell_
+                    // Size of |*buckets_|.
+                    + sizeof(CellIndex) * kNumBuckets;
+  overhead->Add("AllocationRegister", allocated, resident);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_register.h b/base/trace_event/heap_profiler_allocation_register.h
new file mode 100644
index 0000000..7c4ba99
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_register.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_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
+
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// The allocation register keeps track of all allocations that have not been
+// freed. It is a memory map-backed hash table that stores size and context
+// indexed by address. The hash table is tailored specifically for this use
+// case. The common case is that an entry is inserted and removed after a
+// while, lookup without modifying the table is not an intended use case. The
+// hash table is implemented as an array of linked lists. The size of this
+// array is fixed, but it does not limit the amount of entries that can be
+// stored.
+//
+// Replaying a recording of Chrome's allocations and frees against this hash
+// table takes about 15% of the time that it takes to replay them against
+// |std::map|.
+class BASE_EXPORT AllocationRegister {
+ public:
+  // The data stored in the hash table;
+  // contains the details about an allocation.
+  struct Allocation {
+    void* address;
+    size_t size;
+    AllocationContext context;
+  };
+
+  // An iterator that iterates entries in the hash table efficiently, but in no
+  // particular order. It can do this by iterating the cells and ignoring the
+  // linked lists altogether. Instead of checking whether a cell is in the free
+  // list to see if it should be skipped, a null address is used to indicate
+  // that a cell is free.
+  class BASE_EXPORT ConstIterator {
+   public:
+    void operator++();
+    bool operator!=(const ConstIterator& other) const;
+    const Allocation& operator*() const;
+
+   private:
+    friend class AllocationRegister;
+    using CellIndex = uint32_t;
+
+    ConstIterator(const AllocationRegister& alloc_register, CellIndex index);
+
+    const AllocationRegister& register_;
+    CellIndex index_;
+  };
+
+  AllocationRegister();
+  ~AllocationRegister();
+
+  // Inserts allocation details into the table. If the address was present
+  // already, its details are updated. |address| must not be null. (This is
+  // because null is used to mark free cells, to allow efficient iteration of
+  // the hash table.)
+  void Insert(void* address, size_t size, AllocationContext context);
+
+  // Removes the address from the table if it is present. It is ok to call this
+  // with a null pointer.
+  void Remove(void* address);
+
+  ConstIterator begin() const;
+  ConstIterator end() const;
+
+  // Estimates memory overhead including |sizeof(AllocationRegister)|.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) const;
+
+ private:
+  friend class AllocationRegisterTest;
+  using CellIndex = uint32_t;
+
+  // A cell can store allocation details (size and context) by address. Cells
+  // are part of a linked list via the |next| member. This list is either the
+  // list for a particular hash, or the free list. All cells are contiguous in
+  // memory in one big array. Therefore, on 64-bit systems, space can be saved
+  // by storing 32-bit indices instead of pointers as links. Index 0 is used as
+  // the list terminator.
+  struct Cell {
+    CellIndex next;
+    Allocation allocation;
+  };
+
+  // The number of buckets, 2^18, approximately 260 000, has been tuned for
+  // Chrome's typical number of outstanding allocations. (This number varies
+  // between processes. Most processes have a sustained load of ~30k unfreed
+  // allocations, but some processes have peeks around 100k-400k allocations.)
+  // Because of the size of the table, it is likely that every |buckets_|
+  // access and every |cells_| access will incur a cache miss. Microbenchmarks
+  // suggest that it is worthwile to use more memory for the table to avoid
+  // chasing down the linked list, until the size is 2^18. The number of buckets
+  // is a power of two so modular indexing can be done with bitwise and.
+  static const uint32_t kNumBuckets = 0x40000;
+  static const uint32_t kNumBucketsMask = kNumBuckets - 1;
+
+  // Reserve address space to store at most this number of entries. High
+  // capacity does not imply high memory usage due to the access pattern. The
+  // only constraint on the number of cells is that on 32-bit systems address
+  // space is scarce (i.e. reserving 2GiB of address space for the entries is
+  // not an option). A value of ~3M entries is large enough to handle spikes in
+  // the number of allocations, and modest enough to require no more than a few
+  // dozens of MiB of address space.
+  static const uint32_t kNumCells = kNumBuckets * 10;
+
+  // Returns a value in the range [0, kNumBuckets - 1] (inclusive).
+  static uint32_t Hash(void* address);
+
+  // Allocates a region of virtual address space of |size| rounded up to the
+  // system page size. The memory is zeroed by the system. A guard page is
+  // added after the end.
+  static void* AllocateVirtualMemory(size_t size);
+
+  // Frees a region of virtual address space allocated by a call to
+  // |AllocateVirtualMemory|.
+  static void FreeVirtualMemory(void* address, size_t allocated_size);
+
+  // Returns a pointer to the variable that contains or should contain the
+  // index of the cell that stores the entry for |address|. The pointer may
+  // point at an element of |buckets_| or at the |next| member of an element of
+  // |cells_|. If the value pointed at is 0, |address| is not in the table.
+  CellIndex* Lookup(void* address);
+
+  // Takes a cell that is not being used to store an entry (either by recycling
+  // from the free list or by taking a fresh cell) and returns its index.
+  CellIndex GetFreeCell();
+
+  // The array of cells. This array is backed by mmapped memory. Lower indices
+  // are accessed first, higher indices are only accessed when required. In
+  // this way, even if a huge amount of address space has been mmapped, only
+  // the cells that are actually used will be backed by physical memory.
+  Cell* const cells_;
+
+  // The array of indices into |cells_|. |buckets_[Hash(address)]| will contain
+  // the index of the head of the linked list for |Hash(address)|. A value of 0
+  // indicates an empty list. This array is backed by mmapped memory.
+  CellIndex* const buckets_;
+
+  // The head of the free list. This is the index of the cell. A value of 0
+  // means that the free list is empty.
+  CellIndex free_list_;
+
+  // The index of the first element of |cells_| that has not been used before.
+  // If the free list is empty and a new cell is needed, the cell at this index
+  // is used. This is the high water mark for the number of entries stored.
+  CellIndex next_unused_cell_;
+
+  DISALLOW_COPY_AND_ASSIGN(AllocationRegister);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
diff --git a/base/trace_event/heap_profiler_allocation_register_posix.cc b/base/trace_event/heap_profiler_allocation_register_posix.cc
new file mode 100644
index 0000000..bc175e4
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_register_posix.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/heap_profiler_allocation_register.h"
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/bits.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+namespace base {
+namespace trace_event {
+
+namespace {
+size_t GetGuardSize() {
+  return GetPageSize();
+}
+}
+
+// static
+void* AllocationRegister::AllocateVirtualMemory(size_t size) {
+  size = bits::Align(size, GetPageSize());
+
+  // Add space for a guard page at the end.
+  size_t map_size = size + GetGuardSize();
+
+  void* addr = mmap(nullptr, map_size, PROT_READ | PROT_WRITE,
+                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+  PCHECK(addr != MAP_FAILED);
+
+  // Mark the last page of the allocated address space as inaccessible
+  // (PROT_NONE). The read/write accessible space is still at least |min_size|
+  // bytes.
+  void* guard_addr =
+      reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) + size);
+  int result = mprotect(guard_addr, GetGuardSize(), PROT_NONE);
+  PCHECK(result == 0);
+
+  return addr;
+}
+
+// static
+void AllocationRegister::FreeVirtualMemory(void* address,
+                                           size_t allocated_size) {
+  size_t size = bits::Align(allocated_size, GetPageSize()) + GetGuardSize();
+  munmap(address, size);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_register_unittest.cc b/base/trace_event/heap_profiler_allocation_register_unittest.cc
new file mode 100644
index 0000000..6058f47
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_register_unittest.cc
@@ -0,0 +1,229 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_allocation_register.h"
+
+#include "base/process/process_metrics.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+class AllocationRegisterTest : public testing::Test {
+ public:
+  static const uint32_t kNumBuckets = AllocationRegister::kNumBuckets;
+  static const uint32_t kNumCells = AllocationRegister::kNumCells;
+
+  // Returns the number of cells that the |AllocationRegister| can store per
+  // system page.
+  size_t GetNumCellsPerPage() {
+    return GetPageSize() / sizeof(AllocationRegister::Cell);
+  }
+
+  uint32_t GetHighWaterMark(const AllocationRegister& reg) {
+    return reg.next_unused_cell_;
+  }
+};
+
+// Iterates over all entries in the allocation register and returns the bitwise
+// or of all addresses stored in it.
+uintptr_t OrAllAddresses(const AllocationRegister& reg) {
+  uintptr_t acc = 0;
+
+  for (auto i : reg)
+    acc |= reinterpret_cast<uintptr_t>(i.address);
+
+  return acc;
+}
+
+// Iterates over all entries in the allocation register and returns the sum of
+// the sizes of the entries.
+size_t SumAllSizes(const AllocationRegister& reg) {
+  size_t sum = 0;
+
+  for (auto i : reg)
+    sum += i.size;
+
+  return sum;
+}
+
+TEST_F(AllocationRegisterTest, InsertRemove) {
+  AllocationRegister reg;
+  AllocationContext ctx = AllocationContext::Empty();
+
+  EXPECT_EQ(0u, OrAllAddresses(reg));
+
+  reg.Insert(reinterpret_cast<void*>(1), 0, ctx);
+
+  EXPECT_EQ(1u, OrAllAddresses(reg));
+
+  reg.Insert(reinterpret_cast<void*>(2), 0, ctx);
+
+  EXPECT_EQ(3u, OrAllAddresses(reg));
+
+  reg.Insert(reinterpret_cast<void*>(4), 0, ctx);
+
+  EXPECT_EQ(7u, OrAllAddresses(reg));
+
+  reg.Remove(reinterpret_cast<void*>(2));
+
+  EXPECT_EQ(5u, OrAllAddresses(reg));
+
+  reg.Remove(reinterpret_cast<void*>(4));
+
+  EXPECT_EQ(1u, OrAllAddresses(reg));
+
+  reg.Remove(reinterpret_cast<void*>(1));
+
+  EXPECT_EQ(0u, OrAllAddresses(reg));
+}
+
+TEST_F(AllocationRegisterTest, DoubleFreeIsAllowed) {
+  AllocationRegister reg;
+  AllocationContext ctx = AllocationContext::Empty();
+
+  reg.Insert(reinterpret_cast<void*>(1), 0, ctx);
+  reg.Insert(reinterpret_cast<void*>(2), 0, ctx);
+  reg.Remove(reinterpret_cast<void*>(1));
+  reg.Remove(reinterpret_cast<void*>(1));  // Remove for the second time.
+  reg.Remove(reinterpret_cast<void*>(4));  // Remove never inserted address.
+
+  EXPECT_EQ(2u, OrAllAddresses(reg));
+}
+
+TEST_F(AllocationRegisterTest, DoubleInsertOverwrites) {
+  // TODO(ruuda): Although double insert happens in practice, it should not.
+  // Find out the cause and ban double insert if possible.
+  AllocationRegister reg;
+  AllocationContext ctx = AllocationContext::Empty();
+  StackFrame frame1 = "Foo";
+  StackFrame frame2 = "Bar";
+
+  ctx.backtrace.frames[0] = frame1;
+  reg.Insert(reinterpret_cast<void*>(1), 11, ctx);
+
+  auto elem = *reg.begin();
+
+  EXPECT_EQ(frame1, elem.context.backtrace.frames[0]);
+  EXPECT_EQ(11u, elem.size);
+  EXPECT_EQ(reinterpret_cast<void*>(1), elem.address);
+
+  ctx.backtrace.frames[0] = frame2;
+  reg.Insert(reinterpret_cast<void*>(1), 13, ctx);
+
+  elem = *reg.begin();
+
+  EXPECT_EQ(frame2, elem.context.backtrace.frames[0]);
+  EXPECT_EQ(13u, elem.size);
+  EXPECT_EQ(reinterpret_cast<void*>(1), elem.address);
+}
+
+// Check that even if more entries than the number of buckets are inserted, the
+// register still behaves correctly.
+TEST_F(AllocationRegisterTest, InsertRemoveCollisions) {
+  size_t expected_sum = 0;
+  AllocationRegister reg;
+  AllocationContext ctx = AllocationContext::Empty();
+
+  // By inserting 100 more entries than the number of buckets, there will be at
+  // least 100 collisions.
+  for (uintptr_t i = 1; i <= kNumBuckets + 100; i++) {
+    size_t size = i % 31;
+    expected_sum += size;
+    reg.Insert(reinterpret_cast<void*>(i), size, ctx);
+
+    // Don't check the sum on every iteration to keep the test fast.
+    if (i % (1 << 14) == 0)
+      EXPECT_EQ(expected_sum, SumAllSizes(reg));
+  }
+
+  EXPECT_EQ(expected_sum, SumAllSizes(reg));
+
+  for (uintptr_t i = 1; i <= kNumBuckets + 100; i++) {
+    size_t size = i % 31;
+    expected_sum -= size;
+    reg.Remove(reinterpret_cast<void*>(i));
+
+    if (i % (1 << 14) == 0)
+      EXPECT_EQ(expected_sum, SumAllSizes(reg));
+  }
+
+  EXPECT_EQ(expected_sum, SumAllSizes(reg));
+}
+
+// The previous tests are not particularly good for testing iterators, because
+// elements are removed and inserted in the same order, meaning that the cells
+// fill up from low to high index, and are then freed from low to high index.
+// This test removes entries in a different order, to ensure that the iterator
+// skips over the freed cells properly. Then insert again to ensure that the
+// free list is utilised properly.
+TEST_F(AllocationRegisterTest, InsertRemoveRandomOrder) {
+  size_t expected_sum = 0;
+  AllocationRegister reg;
+  AllocationContext ctx = AllocationContext::Empty();
+
+  uintptr_t generator = 3;
+  uintptr_t prime = 1013;
+  uint32_t initial_water_mark = GetHighWaterMark(reg);
+
+  for (uintptr_t i = 2; i < prime; i++) {
+    size_t size = i % 31;
+    expected_sum += size;
+    reg.Insert(reinterpret_cast<void*>(i), size, ctx);
+  }
+
+  // This should have used a fresh slot for each of the |prime - 2| inserts.
+  ASSERT_EQ(prime - 2, GetHighWaterMark(reg) - initial_water_mark);
+
+  // Iterate the numbers 2, 3, ..., prime - 1 in pseudorandom order.
+  for (uintptr_t i = generator; i != 1; i = (i * generator) % prime) {
+    size_t size = i % 31;
+    expected_sum -= size;
+    reg.Remove(reinterpret_cast<void*>(i));
+    EXPECT_EQ(expected_sum, SumAllSizes(reg));
+  }
+
+  ASSERT_EQ(0u, expected_sum);
+
+  // Insert |prime - 2| entries again. This should use cells from the free list,
+  // so the |next_unused_cell_| index should not change.
+  for (uintptr_t i = 2; i < prime; i++)
+    reg.Insert(reinterpret_cast<void*>(i), 0, ctx);
+
+  ASSERT_EQ(prime - 2, GetHighWaterMark(reg) - initial_water_mark);
+
+  // Inserting one more entry should use a fresh cell again.
+  reg.Insert(reinterpret_cast<void*>(prime), 0, ctx);
+  ASSERT_EQ(prime - 1, GetHighWaterMark(reg) - initial_water_mark);
+}
+
+// Check that the process aborts due to hitting the guard page when inserting
+// too many elements.
+#if GTEST_HAS_DEATH_TEST
+TEST_F(AllocationRegisterTest, OverflowDeathTest) {
+  AllocationRegister reg;
+  AllocationContext ctx = AllocationContext::Empty();
+  uintptr_t i;
+
+  // Fill up all of the memory allocated for the register. |kNumCells| minus 1
+  // elements are inserted, because cell 0 is unused, so this should fill up
+  // the available cells exactly.
+  for (i = 1; i < kNumCells; i++) {
+    reg.Insert(reinterpret_cast<void*>(i), 0, ctx);
+  }
+
+  // Adding just one extra element might still work because the allocated memory
+  // is rounded up to the page size. Adding a page full of elements should cause
+  // overflow.
+  const size_t cells_per_page = GetNumCellsPerPage();
+
+  ASSERT_DEATH(for (size_t j = 0; j < cells_per_page; j++) {
+    reg.Insert(reinterpret_cast<void*>(i + j), 0, ctx);
+  }, "");
+}
+#endif
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_allocation_register_win.cc b/base/trace_event/heap_profiler_allocation_register_win.cc
new file mode 100644
index 0000000..5bcac63
--- /dev/null
+++ b/base/trace_event/heap_profiler_allocation_register_win.cc
@@ -0,0 +1,62 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_allocation_register.h"
+
+#include <windows.h>
+
+#include "base/bits.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+size_t GetGuardSize() {
+  return GetPageSize();
+}
+}
+
+// static
+void* AllocationRegister::AllocateVirtualMemory(size_t size) {
+  size = bits::Align(size, GetPageSize());
+
+  // Add space for a guard page at the end.
+  size_t map_size = size + GetGuardSize();
+
+  // Reserve the address space. This does not make the memory usable yet.
+  void* addr = VirtualAlloc(nullptr, map_size, MEM_RESERVE, PAGE_NOACCESS);
+
+  PCHECK(addr != nullptr);
+
+  // Commit the non-guard pages as read-write memory.
+  void* result = VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE);
+
+  PCHECK(result != nullptr);
+
+  // Mark the last page of the allocated address space as guard page. (NB: The
+  // |PAGE_GUARD| flag is not the flag to use here, that flag can be used to
+  // detect and intercept access to a certain memory region. Accessing a
+  // |PAGE_NOACCESS| page will raise a general protection fault.) The
+  // read/write accessible space is still at least |min_size| bytes.
+  void* guard_addr =
+      reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) + size);
+  result = VirtualAlloc(guard_addr, GetGuardSize(), MEM_COMMIT, PAGE_NOACCESS);
+  PCHECK(result != nullptr);
+
+  return addr;
+}
+
+// static
+void AllocationRegister::FreeVirtualMemory(void* address,
+                                           size_t allocated_size) {
+  // For |VirtualFree|, the size passed with |MEM_RELEASE| mut be 0. Windows
+  // automatically frees the entire region that was reserved by the
+  // |VirtualAlloc| with flag |MEM_RESERVE|.
+  VirtualFree(address, 0, MEM_RELEASE);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_heap_dump_writer.cc b/base/trace_event/heap_profiler_heap_dump_writer.cc
new file mode 100644
index 0000000..d69ed7b
--- /dev/null
+++ b/base/trace_event/heap_profiler_heap_dump_writer.cc
@@ -0,0 +1,132 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_heap_dump_writer.h"
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+#include <vector>
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+template <typename T>
+bool PairSizeGt(const std::pair<T, size_t>& lhs,
+                const std::pair<T, size_t>& rhs) {
+  return lhs.second > rhs.second;
+}
+
+// Converts a |hash_map<T, size_t>| into a vector of (T, size_t) pairs that is
+// ordered from high |size_t| to low |size_t|.
+template <typename T>
+std::vector<std::pair<T, size_t>> SortBySizeDescending(
+    const hash_map<T, size_t>& grouped) {
+  std::vector<std::pair<T, size_t>> sorted;
+  sorted.reserve(grouped.size());
+  std::copy(grouped.begin(), grouped.end(), std::back_inserter(sorted));
+  std::sort(sorted.begin(), sorted.end(), PairSizeGt<T>);
+  return sorted;
+}
+
+}  // namespace
+
+HeapDumpWriter::HeapDumpWriter(StackFrameDeduplicator* stack_frame_deduplicator,
+                               TypeNameDeduplicator* type_name_deduplicator)
+    : traced_value_(new TracedValue()),
+      stack_frame_deduplicator_(stack_frame_deduplicator),
+      type_name_deduplicator_(type_name_deduplicator) {}
+
+HeapDumpWriter::~HeapDumpWriter() {}
+
+void HeapDumpWriter::InsertAllocation(const AllocationContext& context,
+                                      size_t size) {
+  bytes_by_context_[context] += size;
+}
+
+scoped_refptr<TracedValue> HeapDumpWriter::WriteHeapDump() {
+  // Group by backtrace and by type ID, and compute the total heap size while
+  // iterating anyway.
+  size_t total_size = 0;
+  hash_map<Backtrace, size_t> bytes_by_backtrace;
+  hash_map<const char*, size_t> bytes_by_type;
+
+  for (auto context_size : bytes_by_context_) {
+    total_size += context_size.second;
+    bytes_by_backtrace[context_size.first.backtrace] += context_size.second;
+    bytes_by_type[context_size.first.type_name] += context_size.second;
+  }
+
+  auto sorted_bytes_by_backtrace = SortBySizeDescending(bytes_by_backtrace);
+  auto sorted_bytes_by_type = SortBySizeDescending(bytes_by_type);
+
+  traced_value_->BeginArray("entries");
+
+  // The global size, no column specified.
+  {
+    traced_value_->BeginDictionary();
+    WriteSize(total_size);
+    traced_value_->EndDictionary();
+  }
+
+  // Entries with the size per backtrace.
+  for (const auto& entry : sorted_bytes_by_backtrace) {
+    traced_value_->BeginDictionary();
+    // Insert a forward reference to the backtrace that will be written to the
+    // |stackFrames| dictionary later on.
+    WriteStackFrameIndex(stack_frame_deduplicator_->Insert(entry.first));
+    WriteSize(entry.second);
+    traced_value_->EndDictionary();
+  }
+
+  // Entries with the size per type.
+  for (const auto& entry : sorted_bytes_by_type) {
+    traced_value_->BeginDictionary();
+    // Insert a forward reference to the type name that will be written to the
+    // trace when it is flushed.
+    WriteTypeId(type_name_deduplicator_->Insert(entry.first));
+    WriteSize(entry.second);
+    traced_value_->EndDictionary();
+  }
+
+  traced_value_->EndArray();  // "entries"
+
+  return traced_value_;
+}
+
+void HeapDumpWriter::WriteStackFrameIndex(int index) {
+  if (index == -1) {
+    // An empty backtrace (which will have index -1) is represented by the empty
+    // string, because there is no leaf frame to reference in |stackFrames|.
+    traced_value_->SetString("bt", "");
+  } else {
+    // Format index of the leaf frame as a string, because |stackFrames| is a
+    // dictionary, not an array.
+    SStringPrintf(&buffer_, "%i", index);
+    traced_value_->SetString("bt", buffer_);
+  }
+}
+
+void HeapDumpWriter::WriteTypeId(int type_id) {
+  // Format the type ID as a string.
+  SStringPrintf(&buffer_, "%i", type_id);
+  traced_value_->SetString("type", buffer_);
+}
+
+void HeapDumpWriter::WriteSize(size_t size) {
+  // Format size as hexadecimal string into |buffer_|.
+  SStringPrintf(&buffer_, "%" PRIx64, static_cast<uint64_t>(size));
+  traced_value_->SetString("size", buffer_);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_heap_dump_writer.h b/base/trace_event/heap_profiler_heap_dump_writer.h
new file mode 100644
index 0000000..c3a7767
--- /dev/null
+++ b/base/trace_event/heap_profiler_heap_dump_writer.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_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+class StackFrameDeduplicator;
+class TracedValue;
+class TypeNameDeduplicator;
+
+// Helper class to dump a snapshot of an |AllocationRegister| or other heap
+// bookkeeping structure into a |TracedValue|. This class is intended to be
+// used as a one-shot local instance on the stack. To write heap dumps, call
+// |InsertAllocation| for every captured allocation, then call |WriteHeapDump|
+// to do the processing and generate a heap dump value for the trace log.
+class BASE_EXPORT HeapDumpWriter {
+ public:
+  // The |StackFrameDeduplicator| and |TypeNameDeduplicator| are not owned. The
+  // heap dump writer assumes exclusive access to them during the lifetime of
+  // the dump writer.
+  HeapDumpWriter(StackFrameDeduplicator* stack_frame_deduplicator,
+                 TypeNameDeduplicator* type_name_deduplicator);
+  ~HeapDumpWriter();
+
+  // Inserts information from which the heap dump will be generated. This method
+  // does minimal processing, so it can be called when a lock is held.
+  void InsertAllocation(const AllocationContext& context, size_t size);
+
+  // Aggregates allocations and writes an "entries" array to a traced value. See
+  // https://goo.gl/jYN4Zn for a description of the format.
+  scoped_refptr<TracedValue> WriteHeapDump();
+
+ private:
+  // Writes a "bt" key that references a stack frame in the |stackFrames|
+  // dictionary.
+  void WriteStackFrameIndex(int index);
+
+  // Writes a "type" key with the stringified type ID.
+  void WriteTypeId(int type_id);
+
+  // Writes a "size" key with value |size| as a hexidecimal string to the traced
+  // value.
+  void WriteSize(size_t size);
+
+  // The value that this heap dumper writes to.
+  const scoped_refptr<TracedValue> traced_value_;
+
+  // Helper for generating the |stackFrames| dictionary. Not owned, must outlive
+  // this heap dump writer instance.
+  StackFrameDeduplicator* const stack_frame_deduplicator_;
+
+  // Helper for converting type names to IDs. Not owned, must outlive this heap
+  // dump writer instance.
+  TypeNameDeduplicator* const type_name_deduplicator_;
+
+  // A map of allocation context to the number of bytes allocated for that
+  // context.
+  hash_map<AllocationContext, size_t> bytes_by_context_;
+
+  // Buffer for converting integers into strings, that is re-used throughout the
+  // dump.
+  std::string buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(HeapDumpWriter);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
diff --git a/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc b/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc
new file mode 100644
index 0000000..c936f4e
--- /dev/null
+++ b/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright 2015 The Chromium Authors. 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>
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_heap_dump_writer.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kBrowserMain[] = "BrowserMain";
+const char kRendererMain[] = "RendererMain";
+const char kCreateWidget[] = "CreateWidget";
+const char kInitialize[] = "Initialize";
+
+const char kInt[] = "int";
+const char kBool[] = "bool";
+const char kString[] = "string";
+
+}  // namespace
+
+namespace base {
+namespace trace_event {
+
+// Asserts that an integer stored in the json as a string has the correct value.
+void AssertIntEq(const DictionaryValue* entry,
+                 const char* key,
+                 int expected_value) {
+  std::string str;
+  ASSERT_TRUE(entry->GetString(key, &str));
+  ASSERT_EQ(expected_value, atoi(str.c_str()));
+}
+
+scoped_ptr<Value> DumpAndReadBack(HeapDumpWriter* writer) {
+  scoped_refptr<TracedValue> traced_value = writer->WriteHeapDump();
+  std::string json;
+  traced_value->AppendAsTraceFormat(&json);
+  return JSONReader::Read(json);
+}
+
+TEST(HeapDumpWriterTest, BacktraceTypeNameTable) {
+  auto sf_deduplicator = make_scoped_refptr(new StackFrameDeduplicator);
+  auto tn_deduplicator = make_scoped_refptr(new TypeNameDeduplicator);
+  HeapDumpWriter writer(sf_deduplicator.get(), tn_deduplicator.get());
+
+  AllocationContext ctx = AllocationContext::Empty();
+  ctx.backtrace.frames[0] = kBrowserMain;
+  ctx.backtrace.frames[1] = kCreateWidget;
+  ctx.type_name = kInt;
+
+  // 10 bytes with context { type: int, bt: [BrowserMain, CreateWidget] }.
+  writer.InsertAllocation(ctx, 2);
+  writer.InsertAllocation(ctx, 3);
+  writer.InsertAllocation(ctx, 5);
+
+  ctx.type_name = kBool;
+
+  // 18 bytes with context { type: bool, bt: [BrowserMain, CreateWidget] }.
+  writer.InsertAllocation(ctx, 7);
+  writer.InsertAllocation(ctx, 11);
+
+  ctx.backtrace.frames[0] = kRendererMain;
+  ctx.backtrace.frames[1] = kInitialize;
+
+  // 30 bytes with context { type: bool, bt: [RendererMain, Initialize] }.
+  writer.InsertAllocation(ctx, 13);
+  writer.InsertAllocation(ctx, 17);
+
+  ctx.type_name = kString;
+
+  // 19 bytes with context { type: string, bt: [RendererMain, Initialize] }.
+  writer.InsertAllocation(ctx, 19);
+
+  // At this point the heap looks like this:
+  //
+  // |        | CrWidget <- BrMain | Init <- RenMain | Sum |
+  // +--------+--------------------+-----------------+-----+
+  // | int    |                 10 |               0 |  10 |
+  // | bool   |                 18 |              30 |  48 |
+  // | string |                  0 |              19 |  19 |
+  // +--------+--------------------+-----------------+-----+
+  // | Sum    |                 28 |              49 |  77 |
+
+  scoped_ptr<Value> heap_dump = DumpAndReadBack(&writer);
+
+  // The json heap dump should at least include this:
+  // {
+  //   "entries": [
+  //     { "size": "4d" },                                    // 77 = 0x4d.
+  //     { "size": "31", "bt": "id_of(Init <- RenMain)" },    // 49 = 0x31.
+  //     { "size": "1c", "bt": "id_of(CrWidget <- BrMain)" }, // 28 = 0x1c.
+  //     { "size": "30", "type": "id_of(bool)" },             // 48 = 0x30.
+  //     { "size": "13", "type": "id_of(string)" },           // 19 = 0x13.
+  //     { "size": "a", "type": "id_of(int)" }                // 10 = 0xa.
+  //   ]
+  // }
+
+  // Get the indices of the backtraces and types by adding them again to the
+  // deduplicator. Because they were added before, the same number is returned.
+  int bt_renderer_main_initialize =
+      sf_deduplicator->Insert({{kRendererMain, kInitialize}});
+  int bt_browser_main_create_widget =
+      sf_deduplicator->Insert({{kBrowserMain, kCreateWidget}});
+  int type_id_int = tn_deduplicator->Insert(kInt);
+  int type_id_bool = tn_deduplicator->Insert(kBool);
+  int type_id_string = tn_deduplicator->Insert(kString);
+
+  const DictionaryValue* dictionary;
+  ASSERT_TRUE(heap_dump->GetAsDictionary(&dictionary));
+
+  const ListValue* entries;
+  ASSERT_TRUE(dictionary->GetList("entries", &entries));
+
+  // Keep counters to verify that every entry is present exactly once.
+  int x4d_seen = 0;
+  int x31_seen = 0;
+  int x1c_seen = 0;
+  int x30_seen = 0;
+  int x13_seen = 0;
+  int xa_seen = 0;
+
+  for (const Value* entry_as_value : *entries) {
+    const DictionaryValue* entry;
+    ASSERT_TRUE(entry_as_value->GetAsDictionary(&entry));
+
+    // The "size" field, not to be confused with |entry->size()| which is the
+    // number of elements in the dictionary.
+    std::string size;
+    ASSERT_TRUE(entry->GetString("size", &size));
+
+    if (size == "4d") {
+      // Total size, should not include any other field.
+      ASSERT_EQ(1u, entry->size());  // Dictionary must have one element.
+      x4d_seen++;
+    } else if (size == "31") {
+      // Entry for backtrace "Initialize <- RendererMain".
+      ASSERT_EQ(2u, entry->size());  // Dictionary must have two elements.
+      AssertIntEq(entry, "bt", bt_renderer_main_initialize);
+      x31_seen++;
+    } else if (size == "1c") {
+      // Entry for backtrace "CreateWidget <- BrowserMain".
+      ASSERT_EQ(2u, entry->size());  // Dictionary must have two elements.
+      AssertIntEq(entry, "bt", bt_browser_main_create_widget);
+      x1c_seen++;
+    } else if (size == "30") {
+      // Entry for type bool.
+      ASSERT_EQ(2u, entry->size());  // Dictionary must have two elements.
+      AssertIntEq(entry, "type", type_id_bool);
+      x30_seen++;
+    } else if (size == "13") {
+      // Entry for type string.
+      ASSERT_EQ(2u, entry->size());  // Dictionary must have two elements.
+      AssertIntEq(entry, "type", type_id_string);
+      x13_seen++;
+    } else if (size == "a") {
+      // Entry for type int.
+      ASSERT_EQ(2u, entry->size());  // Dictionary must have two elements.
+      AssertIntEq(entry, "type", type_id_int);
+      xa_seen++;
+    }
+  }
+
+  ASSERT_EQ(1, x4d_seen);
+  ASSERT_EQ(1, x31_seen);
+  ASSERT_EQ(1, x1c_seen);
+  ASSERT_EQ(1, x30_seen);
+  ASSERT_EQ(1, x13_seen);
+  ASSERT_EQ(1, xa_seen);
+}
+
+// Test that the entry for the empty backtrace ends up in the json with the
+// "bt" field set to the empty string. Also test that an entry for "unknown
+// type" (nullptr type name) does not dereference the null pointer when writing
+// the type names, and that the type ID is 0.
+TEST(HeapDumpWriterTest, EmptyBacktraceIndexIsEmptyString) {
+  auto sf_deduplicator = make_scoped_refptr(new StackFrameDeduplicator);
+  auto tn_deduplicator = make_scoped_refptr(new TypeNameDeduplicator);
+  HeapDumpWriter writer(sf_deduplicator.get(), tn_deduplicator.get());
+
+  // A context with empty backtrace and unknown type (nullptr).
+  AllocationContext ctx = AllocationContext::Empty();
+
+  writer.InsertAllocation(ctx, 1);
+
+  scoped_ptr<Value> heap_dump = DumpAndReadBack(&writer);
+
+  const DictionaryValue* dictionary;
+  ASSERT_TRUE(heap_dump->GetAsDictionary(&dictionary));
+
+  const ListValue* entries;
+  ASSERT_TRUE(dictionary->GetList("entries", &entries));
+
+  int empty_backtrace_seen = 0;
+  int unknown_type_seen = 0;
+
+  for (const Value* entry_as_value : *entries) {
+    const DictionaryValue* entry;
+    ASSERT_TRUE(entry_as_value->GetAsDictionary(&entry));
+
+    // Note that |entry->size()| is the number of elements in the dictionary.
+    if (entry->HasKey("bt") && entry->size() == 2) {
+      std::string backtrace;
+      ASSERT_TRUE(entry->GetString("bt", &backtrace));
+      ASSERT_EQ("", backtrace);
+      empty_backtrace_seen++;
+    }
+
+    if (entry->HasKey("type") && entry->size() == 2) {
+      std::string type_id;
+      ASSERT_TRUE(entry->GetString("type", &type_id));
+      ASSERT_EQ("0", type_id);
+      unknown_type_seen++;
+    }
+  }
+
+  ASSERT_EQ(1, unknown_type_seen);
+  ASSERT_EQ(1, empty_backtrace_seen);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
new file mode 100644
index 0000000..09c4a3e
--- /dev/null
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
@@ -0,0 +1,112 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+
+#include <string>
+#include <utility>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
+                                             int parent_frame_index)
+    : frame(frame), parent_frame_index(parent_frame_index) {}
+StackFrameDeduplicator::FrameNode::~FrameNode() {}
+
+StackFrameDeduplicator::StackFrameDeduplicator() {}
+StackFrameDeduplicator::~StackFrameDeduplicator() {}
+
+int StackFrameDeduplicator::Insert(const Backtrace& bt) {
+  int frame_index = -1;
+  std::map<StackFrame, int>* nodes = &roots_;
+
+  for (size_t i = 0; i < arraysize(bt.frames); i++) {
+    if (!bt.frames[i])
+      break;
+
+    auto node = nodes->find(bt.frames[i]);
+    if (node == nodes->end()) {
+      // There is no tree node for this frame yet, create it. The parent node
+      // is the node associated with the previous frame.
+      FrameNode frame_node(bt.frames[i], frame_index);
+
+      // The new frame node will be appended, so its index is the current size
+      // of the vector.
+      frame_index = static_cast<int>(frames_.size());
+
+      // Add the node to the trie so it will be found next time.
+      nodes->insert(std::make_pair(bt.frames[i], frame_index));
+
+      // Append the node after modifying |nodes|, because the |frames_| vector
+      // might need to resize, and this invalidates the |nodes| pointer.
+      frames_.push_back(frame_node);
+    } else {
+      // A tree node for this frame exists. Look for the next one.
+      frame_index = node->second;
+    }
+
+    nodes = &frames_[frame_index].children;
+  }
+
+  return frame_index;
+}
+
+void StackFrameDeduplicator::AppendAsTraceFormat(std::string* out) const {
+  out->append("{");  // Begin the |stackFrames| dictionary.
+
+  int i = 0;
+  auto frame_node = begin();
+  auto it_end = end();
+  std::string stringify_buffer;
+
+  while (frame_node != it_end) {
+    // The |stackFrames| format is a dictionary, not an array, so the
+    // keys are stringified indices. Write the index manually, then use
+    // |TracedValue| to format the object. This is to avoid building the
+    // entire dictionary as a |TracedValue| in memory.
+    SStringPrintf(&stringify_buffer, "\"%d\":", i);
+    out->append(stringify_buffer);
+
+    scoped_refptr<TracedValue> frame_node_value = new TracedValue;
+    frame_node_value->SetString("name", frame_node->frame);
+    if (frame_node->parent_frame_index >= 0) {
+      SStringPrintf(&stringify_buffer, "%d", frame_node->parent_frame_index);
+      frame_node_value->SetString("parent", stringify_buffer);
+    }
+    frame_node_value->AppendAsTraceFormat(out);
+
+    i++;
+    frame_node++;
+
+    if (frame_node != it_end)
+      out->append(",");
+  }
+
+  out->append("}");  // End the |stackFrames| dictionary.
+}
+
+void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  // The sizes here are only estimates; they fail to take into account the
+  // overhead of the tree nodes for the map, but as an estimate this should be
+  // fine.
+  size_t maps_size = roots_.size() * sizeof(std::pair<StackFrame, int>);
+  size_t frames_allocated = frames_.capacity() * sizeof(FrameNode);
+  size_t frames_resident = frames_.size() * sizeof(FrameNode);
+
+  for (const FrameNode& node : frames_)
+    maps_size += node.children.size() * sizeof(std::pair<StackFrame, int>);
+
+  overhead->Add("StackFrameDeduplicator",
+                sizeof(StackFrameDeduplicator) + maps_size + frames_allocated,
+                sizeof(StackFrameDeduplicator) + maps_size + frames_resident);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.h b/base/trace_event/heap_profiler_stack_frame_deduplicator.h
new file mode 100644
index 0000000..a7b00ca
--- /dev/null
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.h
@@ -0,0 +1,77 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// A data structure that allows grouping a set of backtraces in a space-
+// efficient manner by creating a call tree and writing it as a set of (node,
+// parent) pairs. The tree nodes reference both parent and children. The parent
+// is referenced by index into |frames_|. The children are referenced via a map
+// of |StackFrame|s to index into |frames_|. So there is a trie for bottum-up
+// lookup of a backtrace for deduplication, and a tree for compact storage in
+// the trace log.
+class BASE_EXPORT StackFrameDeduplicator : public ConvertableToTraceFormat {
+ public:
+  // A node in the call tree.
+  struct FrameNode {
+    FrameNode(StackFrame frame, int parent_frame_index);
+    ~FrameNode();
+
+    StackFrame frame;
+
+    // The index of the parent stack frame in |frames_|, or -1 if there is no
+    // parent frame (when it is at the bottom of the call stack).
+    int parent_frame_index;
+
+    // Indices into |frames_| of frames called from the current frame.
+    std::map<StackFrame, int> children;
+  };
+
+  using ConstIterator = std::vector<FrameNode>::const_iterator;
+
+  StackFrameDeduplicator();
+
+  // Inserts a backtrace and returns the index of its leaf node in |frames_|.
+  // Returns -1 if the backtrace is empty.
+  int Insert(const Backtrace& bt);
+
+  // Iterators over the frame nodes in the call tree.
+  ConstIterator begin() const { return frames_.begin(); }
+  ConstIterator end() const { return frames_.end(); }
+
+  // Writes the |stackFrames| dictionary as defined in https://goo.gl/GerkV8 to
+  // the trace log.
+  void AppendAsTraceFormat(std::string* out) const override;
+
+  // Estimates memory overhead including |sizeof(StackFrameDeduplicator)|.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+ private:
+  ~StackFrameDeduplicator() override;
+
+  std::map<StackFrame, int> roots_;
+  std::vector<FrameNode> frames_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackFrameDeduplicator);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
new file mode 100644
index 0000000..b87c7b1
--- /dev/null
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright 2015 The Chromium Authors. All 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/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kBrowserMain[] = "BrowserMain";
+const char kRendererMain[] = "RendererMain";
+const char kCreateWidget[] = "CreateWidget";
+const char kInitialize[] = "Initialize";
+const char kMalloc[] = "malloc";
+
+class StackFrameDeduplicatorTest : public testing::Test {};
+
+TEST_F(StackFrameDeduplicatorTest, SingleBacktrace) {
+  Backtrace bt = {
+      {kBrowserMain, kCreateWidget, kMalloc, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+  // The call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   CreateWidget [1]
+  //     malloc [2]
+
+  scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+  ASSERT_EQ(2, dedup->Insert(bt));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kMalloc, (iter + 2)->frame);
+  ASSERT_EQ(1, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(iter + 3, dedup->end());
+}
+
+// Test that there can be different call trees (there can be multiple bottom
+// frames). Also verify that frames with the same name but a different caller
+// are represented as distinct nodes.
+TEST_F(StackFrameDeduplicatorTest, MultipleRoots) {
+  Backtrace bt0 = {{kBrowserMain, kCreateWidget, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+  Backtrace bt1 = {{kRendererMain, kCreateWidget, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+  // The call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   CreateWidget [1]
+  // RendererMain [2]
+  //   CreateWidget [3]
+  //
+  // Note that there will be two instances of CreateWidget,
+  // with different parents.
+
+  scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+  ASSERT_EQ(1, dedup->Insert(bt0));
+  ASSERT_EQ(3, dedup->Insert(bt1));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kRendererMain, (iter + 2)->frame);
+  ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
+  ASSERT_EQ(2, (iter + 3)->parent_frame_index);
+
+  ASSERT_EQ(iter + 4, dedup->end());
+}
+
+TEST_F(StackFrameDeduplicatorTest, Deduplication) {
+  Backtrace bt0 = {{kBrowserMain, kCreateWidget, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+  Backtrace bt1 = {{kBrowserMain, kInitialize, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+  // The call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   CreateWidget [1]
+  //   Initialize [2]
+  //
+  // Note that BrowserMain will be re-used.
+
+  scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+  ASSERT_EQ(1, dedup->Insert(bt0));
+  ASSERT_EQ(2, dedup->Insert(bt1));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kInitialize, (iter + 2)->frame);
+  ASSERT_EQ(0, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(iter + 3, dedup->end());
+
+  // Inserting the same backtrace again should return the index of the existing
+  // node.
+  ASSERT_EQ(1, dedup->Insert(bt0));
+  ASSERT_EQ(2, dedup->Insert(bt1));
+  ASSERT_EQ(dedup->begin() + 3, dedup->end());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator.cc b/base/trace_event/heap_profiler_type_name_deduplicator.cc
new file mode 100644
index 0000000..17c3cee
--- /dev/null
+++ b/base/trace_event/heap_profiler_type_name_deduplicator.cc
@@ -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.
+
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+
+#include <stdlib.h>
+#include <string>
+#include <utility>
+
+#include "base/json/string_escape.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+TypeNameDeduplicator::TypeNameDeduplicator() {
+  // A null pointer has type ID 0 ("unknown type");
+  type_ids_.insert(std::make_pair(nullptr, 0));
+}
+
+TypeNameDeduplicator::~TypeNameDeduplicator() {}
+
+int TypeNameDeduplicator::Insert(const char* type_name) {
+  auto result = type_ids_.insert(std::make_pair(type_name, 0));
+  auto& elem = result.first;
+  bool did_not_exist_before = result.second;
+
+  if (did_not_exist_before) {
+    // The type IDs are assigned sequentially and they are zero-based, so
+    // |size() - 1| is the ID of the new element.
+    elem->second = static_cast<int>(type_ids_.size() - 1);
+  }
+
+  return elem->second;
+}
+
+void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const {
+  out->append("{");  // Begin the type names dictionary.
+
+  auto it = type_ids_.begin();
+  std::string buffer;
+
+  // Write the first entry manually; the null pointer must not be dereferenced.
+  // (The first entry is the null pointer because a |std::map| is ordered.)
+  it++;
+  out->append("\"0\":\"[unknown]\"");
+
+  for (; it != type_ids_.end(); it++) {
+    // Type IDs in the trace are strings, write them as stringified keys of
+    // a dictionary.
+    SStringPrintf(&buffer, ",\"%d\":", it->second);
+
+    // |EscapeJSONString| appends, it does not overwrite |buffer|.
+    bool put_in_quotes = true;
+    EscapeJSONString(it->first, put_in_quotes, &buffer);
+    out->append(buffer);
+  }
+
+  out->append("}");  // End the type names dictionary.
+}
+
+void TypeNameDeduplicator::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  // The size here is only an estimate; it fails to take into account the size
+  // of the tree nodes for the map, but as an estimate this should be fine.
+  size_t map_size = type_ids_.size() * sizeof(std::pair<const char*, int>);
+
+  overhead->Add("TypeNameDeduplicator",
+                sizeof(TypeNameDeduplicator) + map_size);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator.h b/base/trace_event/heap_profiler_type_name_deduplicator.h
new file mode 100644
index 0000000..317ea5e
--- /dev/null
+++ b/base/trace_event/heap_profiler_type_name_deduplicator.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_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// Data structure that assigns a unique numeric ID to |const char*|s.
+class BASE_EXPORT TypeNameDeduplicator : public ConvertableToTraceFormat {
+ public:
+  TypeNameDeduplicator();
+
+  // Inserts a type name and returns its ID.
+  int Insert(const char* type_name);
+
+  // Estimates memory overhead including |sizeof(TypeNameDeduplicator)|.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+ private:
+  ~TypeNameDeduplicator() override;
+
+  // Writes the type ID -> type name mapping to the trace log.
+  void AppendAsTraceFormat(std::string* out) const override;
+
+  // Map from type name to type ID.
+  std::map<const char*, int> type_ids_;
+
+  DISALLOW_COPY_AND_ASSIGN(TypeNameDeduplicator);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc b/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
new file mode 100644
index 0000000..82c8fb5
--- /dev/null
+++ b/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
@@ -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.
+
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kInt[] = "int";
+const char kBool[] = "bool";
+const char kString[] = "string";
+const char kNeedsEscape[] = "\"quotes\"";
+
+scoped_ptr<Value> DumpAndReadBack(const ConvertableToTraceFormat& convertable) {
+  std::string json;
+  convertable.AppendAsTraceFormat(&json);
+  return JSONReader::Read(json);
+}
+
+TEST(TypeNameDeduplicatorTest, Deduplication) {
+  // The type IDs should be like this:
+  // 0: [unknown]
+  // 1: int
+  // 2: bool
+  // 3: string
+
+  scoped_refptr<TypeNameDeduplicator> dedup = new TypeNameDeduplicator;
+  ASSERT_EQ(1, dedup->Insert(kInt));
+  ASSERT_EQ(2, dedup->Insert(kBool));
+  ASSERT_EQ(3, dedup->Insert(kString));
+
+  // Inserting again should return the same IDs.
+  ASSERT_EQ(2, dedup->Insert(kBool));
+  ASSERT_EQ(1, dedup->Insert(kInt));
+  ASSERT_EQ(3, dedup->Insert(kString));
+
+  // A null pointer should yield type ID 0.
+  ASSERT_EQ(0, dedup->Insert(nullptr));
+}
+
+TEST(TypeNameDeduplicatorTest, EscapeTypeName) {
+  scoped_refptr<TypeNameDeduplicator> dedup = new TypeNameDeduplicator;
+  ASSERT_EQ(1, dedup->Insert(kNeedsEscape));
+
+  // Reading json should not fail, because the type name should have been
+  // escaped properly.
+  scoped_ptr<Value> type_names = DumpAndReadBack(*dedup);
+  ASSERT_NE(nullptr, type_names);
+
+  const DictionaryValue* dictionary;
+  ASSERT_TRUE(type_names->GetAsDictionary(&dictionary));
+
+  // When the type name was inserted, it got ID 1. The exported key "1"
+  // should contain the name, with quotes.
+  std::string type_name;
+  ASSERT_TRUE(dictionary->GetString("1", &type_name));
+  ASSERT_EQ("\"quotes\"", type_name);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/java_heap_dump_provider_android.cc b/base/trace_event/java_heap_dump_provider_android.cc
index 2a84b81..684f730 100644
--- a/base/trace_event/java_heap_dump_provider_android.cc
+++ b/base/trace_event/java_heap_dump_provider_android.cc
@@ -24,18 +24,22 @@
 
 // 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");
-
+bool JavaHeapDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
+                                        ProcessMemoryDump* pmd) {
   // These numbers come from java.lang.Runtime stats.
   long total_heap_size = 0;
   long free_heap_size = 0;
   android::JavaRuntime::GetMemoryUsage(&total_heap_size, &free_heap_size);
-  dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
-                  MemoryAllocatorDump::kUnitsBytes, total_heap_size);
-  dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
-                  MemoryAllocatorDump::kUnitsBytes,
-                  total_heap_size - free_heap_size);
+
+  MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("java_heap");
+  outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes, total_heap_size);
+
+  MemoryAllocatorDump* inner_dump =
+      pmd->CreateAllocatorDump("java_heap/allocated_objects");
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes,
+                        total_heap_size - free_heap_size);
   return true;
 }
 
diff --git a/base/trace_event/java_heap_dump_provider_android.h b/base/trace_event/java_heap_dump_provider_android.h
index 2f31047..e69c281 100644
--- a/base/trace_event/java_heap_dump_provider_android.h
+++ b/base/trace_event/java_heap_dump_provider_android.h
@@ -17,7 +17,8 @@
   static JavaHeapDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override;
 
  private:
   friend struct DefaultSingletonTraits<JavaHeapDumpProvider>;
diff --git a/base/trace_event/java_heap_dump_provider_android_unittest.cc b/base/trace_event/java_heap_dump_provider_android_unittest.cc
index bbefba5..35f3f17 100644
--- a/base/trace_event/java_heap_dump_provider_android_unittest.cc
+++ b/base/trace_event/java_heap_dump_provider_android_unittest.cc
@@ -13,8 +13,9 @@
 TEST(JavaHeapDumpProviderTest, JavaHeapDump) {
   auto jhdp = JavaHeapDumpProvider::GetInstance();
   scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
+  MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
 
-  jhdp->OnMemoryDump(pmd.get());
+  jhdp->OnMemoryDump(dump_args, pmd.get());
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
index c04b858..5279ab0 100644
--- a/base/trace_event/malloc_dump_provider.cc
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -4,46 +4,81 @@
 
 #include "base/trace_event/malloc_dump_provider.h"
 
+#if defined(OS_MACOSX)
+#include <malloc/malloc.h>
+#else
 #include <malloc.h>
+#endif
 
+#include "base/allocator/allocator_extension_thunks.h"
 #include "base/trace_event/process_memory_dump.h"
 
 namespace base {
 namespace trace_event {
 
 // static
+const char MallocDumpProvider::kAllocatedObjects[] = "malloc/allocated_objects";
+
+// static
 MallocDumpProvider* MallocDumpProvider::GetInstance() {
   return Singleton<MallocDumpProvider,
                    LeakySingletonTraits<MallocDumpProvider>>::get();
 }
 
-MallocDumpProvider::MallocDumpProvider() {
-}
+MallocDumpProvider::MallocDumpProvider() {}
 
-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);
+bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
+                                      ProcessMemoryDump* pmd) {
+  size_t total_virtual_size = 0;
+  size_t resident_size = 0;
+  size_t allocated_objects_size = 0;
+#if defined(OS_MACOSX) || defined(OS_IOS)
+  malloc_statistics_t stats = {0};
+  malloc_zone_statistics(nullptr, &stats);
+  total_virtual_size = stats.size_allocated;
+  resident_size = stats.size_in_use;
+  allocated_objects_size = stats.size_in_use;
+#else
+  allocator::thunks::GetNumericPropertyFunction get_property_function =
+      allocator::thunks::GetGetNumericPropertyFunction();
+  if (get_property_function) {
+    // If the function is not null then tcmalloc is used. See
+    // MallocExtension::getNumericProperty.
+    bool res = get_property_function("generic.heap_size", &total_virtual_size);
+    DCHECK(res);
+    res = get_property_function("generic.total_physical_bytes", &resident_size);
+    DCHECK(res);
+    res = get_property_function("generic.current_allocated_bytes",
+                                &allocated_objects_size);
+    DCHECK(res);
+  } else {
+    struct mallinfo info = mallinfo();
+    DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
 
-  MemoryAllocatorDump* dump = pmd->CreateAllocatorDump("malloc");
-  if (!dump)
-    return false;
+    // In case of Android's jemalloc |arena| is 0 and the outer pages size is
+    // reported by |hblkhd|. In case of dlmalloc the total is given by
+    // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF.
+    total_virtual_size = info.arena + info.hblkhd;
+    resident_size = info.uordblks;
+    allocated_objects_size = info.uordblks;
+  }
+#endif
 
-  // 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);
+  MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc");
+  outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes,
+                        total_virtual_size);
+  outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes, resident_size);
 
   // Total allocated space is given by |uordblks|.
-  dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
-                  MemoryAllocatorDump::kUnitsBytes, info.uordblks);
+  MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects);
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes,
+                        allocated_objects_size);
 
   return true;
 }
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h
index ec8683a..63fc1b0 100644
--- a/base/trace_event/malloc_dump_provider.h
+++ b/base/trace_event/malloc_dump_provider.h
@@ -7,8 +7,15 @@
 
 #include <istream>
 
+#include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/trace_event/memory_dump_provider.h"
+#include "build/build_config.h"
+
+#if defined(OS_LINUX) || defined(OS_ANDROID) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS))
+#define MALLOC_MEMORY_TRACING_SUPPORTED
+#endif
 
 namespace base {
 namespace trace_event {
@@ -16,10 +23,15 @@
 // Dump provider which collects process-wide memory stats.
 class BASE_EXPORT MallocDumpProvider : public MemoryDumpProvider {
  public:
+  // Name of the allocated_objects dump. Use this to declare suballocator dumps
+  // from other dump providers.
+  static const char kAllocatedObjects[];
+
   static MallocDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override;
 
  private:
   friend struct DefaultSingletonTraits<MallocDumpProvider>;
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
index edec31b..703fc65 100644
--- a/base/trace_event/memory_allocator_dump.cc
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -15,103 +15,81 @@
 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::kNameSize[] = "size";
+const char MemoryAllocatorDump::kNameObjectCount[] = "object_count";
 const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
 const char MemoryAllocatorDump::kTypeString[] = "string";
 const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
 const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
 
 MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
-                                         ProcessMemoryDump* process_memory_dump)
-    : absolute_name_(absolute_name), process_memory_dump_(process_memory_dump) {
+                                         ProcessMemoryDump* process_memory_dump,
+                                         const MemoryAllocatorDumpGuid& guid)
+    : absolute_name_(absolute_name),
+      process_memory_dump_(process_memory_dump),
+      attributes_(new TracedValue),
+      guid_(guid) {
   // The |absolute_name| cannot be empty.
   DCHECK(!absolute_name.empty());
 
   // The |absolute_name| can contain slash separator, but not leading or
   // trailing ones.
   DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
+}
 
-  // Dots are not allowed anywhere as the underlying base::DictionaryValue
-  // would treat them magically and split in sub-nodes, which is not intended.
-  DCHECK_EQ(std::string::npos, absolute_name.find_first_of('.'));
+// If the caller didn't provide a guid, make one up by hashing the
+// absolute_name with the current PID.
+// Rationale: |absolute_name| is already supposed to be unique within a
+// process, the pid will make it unique among all processes.
+MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
+                                         ProcessMemoryDump* process_memory_dump)
+    : MemoryAllocatorDump(absolute_name,
+                          process_memory_dump,
+                          MemoryAllocatorDumpGuid(StringPrintf(
+                              "%d:%s",
+                              TraceLog::GetInstance()->process_id(),
+                              absolute_name.c_str()))) {
+  string_conversion_buffer_.reserve(16);
 }
 
 MemoryAllocatorDump::~MemoryAllocatorDump() {
 }
 
-void MemoryAllocatorDump::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,
+void MemoryAllocatorDump::AddScalar(const char* name,
                                     const char* units,
                                     uint64 value) {
-  scoped_ptr<Value> hex_value(new StringValue(StringPrintf("%" PRIx64, value)));
-  Add(name, kTypeScalar, units, hex_value.Pass());
+  SStringPrintf(&string_conversion_buffer_, "%" PRIx64, value);
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeScalar);
+  attributes_->SetString("units", units);
+  attributes_->SetString("value", string_conversion_buffer_);
+  attributes_->EndDictionary();
 }
 
-void MemoryAllocatorDump::AddString(const std::string& name,
+void MemoryAllocatorDump::AddScalarF(const char* name,
+                                     const char* units,
+                                     double value) {
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeScalar);
+  attributes_->SetString("units", units);
+  attributes_->SetDouble("value", value);
+  attributes_->EndDictionary();
+}
+
+void MemoryAllocatorDump::AddString(const char* name,
                                     const char* units,
                                     const std::string& value) {
-  scoped_ptr<Value> str_value(new StringValue(value));
-  Add(name, kTypeString, units, str_value.Pass());
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeString);
+  attributes_->SetString("units", units);
+  attributes_->SetString("value", value);
+  attributes_->EndDictionary();
 }
 
 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->BeginDictionaryWithCopiedName(absolute_name_);
+  value->SetString("guid", guid_.ToString());
+  value->SetValue("attrs", *attributes_);
   value->EndDictionary();  // "allocator_name/heap_subheap": { ... }
 }
 
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
index 1bb27f9..6ad3d64 100644
--- a/base/trace_event/memory_allocator_dump.h
+++ b/base/trace_event/memory_allocator_dump.h
@@ -5,9 +5,13 @@
 #ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
 #define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
 
+#include <string>
+
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
 #include "base/values.h"
 
 namespace base {
@@ -22,44 +26,38 @@
  public:
   // MemoryAllocatorDump is owned by ProcessMemoryDump.
   MemoryAllocatorDump(const std::string& absolute_name,
+                      ProcessMemoryDump* process_memory_dump,
+                      const MemoryAllocatorDumpGuid& guid);
+  MemoryAllocatorDump(const std::string& absolute_name,
                       ProcessMemoryDump* process_memory_dump);
   ~MemoryAllocatorDump();
 
-  // Standard attribute name to model total space requested by the allocator
-  // (e.g., amount of pages requested to the system).
-  static const char kNameOuterSize[];
+  // Standard attribute |name|s for the AddScalar and AddString() methods.
+  static const char kNameSize[];          // To represent allocated space.
+  static const char kNameObjectCount[];   // To represent number of objects.
 
-  // Standard attribute 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.
+  // Standard attribute |unit|s for the AddScalar and AddString() methods.
   static const char kUnitsBytes[];    // Unit name to represent bytes.
   static const char kUnitsObjects[];  // Unit name to represent #objects.
 
+  // Constants used only internally and by tests.
+  static const char kTypeScalar[];  // Type name for scalar attributes.
+  static const char kTypeString[];  // Type name for string attributes.
+
+  // Setters for scalar attributes. Some examples:
+  // - "size" column (all dumps are expected to have at least this one):
+  //     AddScalar(kNameSize, kUnitsBytes, 1234);
+  // - Some extra-column reporting internal details of the subsystem:
+  //    AddScalar("number_of_freelist_entires", kUnitsObjects, 42)
+  // - Other informational column (will not be auto-added in the UI)
+  //    AddScalarF("kittens_ratio", "ratio", 42.0f)
+  void AddScalar(const char* name, const char* units, uint64 value);
+  void AddScalarF(const char* name, const char* units, double value);
+  void AddString(const char* name, const char* units, const std::string& value);
+
   // Absolute name, unique within the scope of an entire ProcessMemoryDump.
   const std::string& absolute_name() const { return absolute_name_; }
 
-  // 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;
 
@@ -68,10 +66,25 @@
     return process_memory_dump_;
   }
 
+  // |guid| is an optional global dump identifier, unique across all processes
+  // within the scope of a global dump. It is only required when using the
+  // graph APIs (see TODO_method_name) to express retention / suballocation or
+  // cross process sharing. See crbug.com/492102 for design docs.
+  // Subsequent MemoryAllocatorDump(s) with the same |absolute_name| are
+  // expected to have the same guid.
+  const MemoryAllocatorDumpGuid& guid() const { return guid_; }
+
+  TracedValue* attributes_for_testing() const { return attributes_.get(); }
+
  private:
   const std::string absolute_name_;
   ProcessMemoryDump* const process_memory_dump_;  // Not owned (PMD owns this).
-  DictionaryValue attributes_;
+  scoped_refptr<TracedValue> attributes_;
+  MemoryAllocatorDumpGuid guid_;
+
+  // A local buffer for Sprintf conversion on fastpath. Avoids allocating
+  // temporary strings on each AddScalar() call.
+  std::string string_conversion_buffer_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
 };
diff --git a/base/trace_event/memory_allocator_dump_guid.cc b/base/trace_event/memory_allocator_dump_guid.cc
new file mode 100644
index 0000000..d4ed900
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump_guid.cc
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump_guid.h"
+
+#include "base/format_macros.h"
+#include "base/sha1.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+uint64 HashString(const std::string& str) {
+  uint64 hash[(kSHA1Length + sizeof(uint64) - 1) / sizeof(uint64)] = { 0 };
+  SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.data()), str.size(),
+                reinterpret_cast<unsigned char*>(hash));
+  return hash[0];
+}
+}  // namespace
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(uint64 guid) : guid_(guid) {
+}
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid()
+    : MemoryAllocatorDumpGuid(0u) {
+}
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(const std::string& guid_str)
+    : MemoryAllocatorDumpGuid(HashString(guid_str)) {
+}
+
+std::string MemoryAllocatorDumpGuid::ToString() const {
+  return StringPrintf("%" PRIx64, guid_);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_allocator_dump_guid.h b/base/trace_event/memory_allocator_dump_guid.h
new file mode 100644
index 0000000..634ca81
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump_guid.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_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
+#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT MemoryAllocatorDumpGuid {
+ public:
+  MemoryAllocatorDumpGuid();
+  explicit MemoryAllocatorDumpGuid(uint64 guid);
+
+  // Utility ctor to hash a GUID if the caller prefers a string. The caller
+  // still has to ensure that |guid_str| is unique, per snapshot, within the
+  // global scope of all the traced processes.
+  explicit MemoryAllocatorDumpGuid(const std::string& guid_str);
+
+  uint64 ToUint64() const { return guid_; }
+
+  // Returns a (hex-encoded) string representation of the guid.
+  std::string ToString() const;
+
+  bool empty() const { return guid_ == 0u; }
+
+  bool operator==(const MemoryAllocatorDumpGuid& other) const {
+    return guid_ == other.guid_;
+  }
+
+  bool operator!=(const MemoryAllocatorDumpGuid& other) const {
+    return !(*this == other);
+  }
+
+ private:
+  uint64 guid_;
+
+  // Deliberately copy-able.
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
index 0b2cbdf..124de0d 100644
--- a/base/trace_event/memory_allocator_dump_unittest.cc
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -6,10 +6,12 @@
 
 #include "base/format_macros.h"
 #include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/memory_dump_session_state.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -19,26 +21,24 @@
 
 class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
  public:
-  bool OnMemoryDump(ProcessMemoryDump* pmd) override {
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override {
     MemoryAllocatorDump* root_heap =
         pmd->CreateAllocatorDump("foobar_allocator");
 
-    root_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+    root_heap->AddScalar(MemoryAllocatorDump::kNameSize,
                          MemoryAllocatorDump::kUnitsBytes, 4096);
-    root_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
-                         MemoryAllocatorDump::kUnitsBytes, 1000);
-    root_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+    root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
                          MemoryAllocatorDump::kUnitsObjects, 42);
     root_heap->AddScalar("attr1", "units1", 1234);
     root_heap->AddString("attr2", "units2", "string_value");
+    root_heap->AddScalarF("attr3", "units3", 42.5f);
 
     MemoryAllocatorDump* sub_heap =
         pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
-    sub_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameSize,
                         MemoryAllocatorDump::kUnitsBytes, 1);
-    sub_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
-                        MemoryAllocatorDump::kUnitsBytes, 2);
-    sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
                         MemoryAllocatorDump::kUnitsObjects, 3);
 
     pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
@@ -49,40 +49,86 @@
   }
 };
 
-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;
+scoped_ptr<Value> CheckAttribute(const MemoryAllocatorDump* dump,
+                                 const std::string& name,
+                                 const char* expected_type,
+                                 const char* expected_units) {
+  scoped_ptr<Value> raw_attrs = dump->attributes_for_testing()->ToBaseValue();
+  DictionaryValue* args = nullptr;
+  DictionaryValue* arg = nullptr;
+  std::string arg_value;
+  const Value* out_value = nullptr;
+  EXPECT_TRUE(raw_attrs->GetAsDictionary(&args));
+  EXPECT_TRUE(args->GetDictionary(name, &arg));
+  EXPECT_TRUE(arg->GetString("type", &arg_value));
+  EXPECT_EQ(expected_type, arg_value);
+  EXPECT_TRUE(arg->GetString("units", &arg_value));
+  EXPECT_EQ(expected_units, arg_value);
+  EXPECT_TRUE(arg->Get("value", &out_value));
+  return out_value ? out_value->CreateDeepCopy() : scoped_ptr<Value>();
+}
+
+void CheckString(const MemoryAllocatorDump* dump,
+                 const std::string& name,
+                 const char* expected_type,
+                 const char* expected_units,
+                 const std::string& expected_value) {
   std::string attr_str_value;
-  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));
+  auto attr_value = CheckAttribute(dump, name, expected_type, expected_units);
   EXPECT_TRUE(attr_value->GetAsString(&attr_str_value));
   EXPECT_EQ(expected_value, attr_str_value);
 }
 
-void 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));
+void CheckScalar(const MemoryAllocatorDump* dump,
+                 const std::string& name,
+                 const char* expected_units,
+                 uint64 expected_value) {
+  CheckString(dump, name, MemoryAllocatorDump::kTypeScalar, expected_units,
+              StringPrintf("%" PRIx64, expected_value));
 }
+
+void CheckScalarF(const MemoryAllocatorDump* dump,
+                  const std::string& name,
+                  const char* expected_units,
+                  double expected_value) {
+  auto attr_value = CheckAttribute(dump, name, MemoryAllocatorDump::kTypeScalar,
+                                   expected_units);
+  double attr_double_value;
+  EXPECT_TRUE(attr_value->GetAsDouble(&attr_double_value));
+  EXPECT_EQ(expected_value, attr_double_value);
+}
+
 }  // namespace
 
+TEST(MemoryAllocatorDumpTest, GuidGeneration) {
+  scoped_ptr<MemoryAllocatorDump> mad(
+      new MemoryAllocatorDump("foo", nullptr, MemoryAllocatorDumpGuid(0x42u)));
+  ASSERT_EQ("42", mad->guid().ToString());
+
+  // If the dumper does not provide a Guid, the MAD will make one up on the
+  // flight. Furthermore that Guid will stay stable across across multiple
+  // snapshots if the |absolute_name| of the dump doesn't change
+  mad.reset(new MemoryAllocatorDump("bar", nullptr));
+  const MemoryAllocatorDumpGuid guid_bar = mad->guid();
+  ASSERT_FALSE(guid_bar.empty());
+  ASSERT_FALSE(guid_bar.ToString().empty());
+  ASSERT_EQ(guid_bar, mad->guid());
+
+  mad.reset(new MemoryAllocatorDump("bar", nullptr));
+  const MemoryAllocatorDumpGuid guid_bar_2 = mad->guid();
+  ASSERT_EQ(guid_bar, guid_bar_2);
+
+  mad.reset(new MemoryAllocatorDump("baz", nullptr));
+  const MemoryAllocatorDumpGuid guid_baz = mad->guid();
+  ASSERT_NE(guid_bar, guid_baz);
+}
+
 TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
   FakeMemoryAllocatorDumpProvider fmadp;
-  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+  ProcessMemoryDump pmd(new MemoryDumpSessionState(nullptr, nullptr));
+  MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
 
-  fmadp.OnMemoryDump(&pmd);
+  fmadp.OnMemoryDump(dump_args, &pmd);
 
   ASSERT_EQ(3u, pmd.allocator_dumps().size());
 
@@ -90,44 +136,32 @@
       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");
+  CheckScalar(root_heap, MemoryAllocatorDump::kNameSize,
+              MemoryAllocatorDump::kUnitsBytes, 4096);
+  CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectCount,
+              MemoryAllocatorDump::kUnitsObjects, 42);
+  CheckScalar(root_heap, "attr1", "units1", 1234);
+  CheckString(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2",
+              "string_value");
+  CheckScalarF(root_heap, "attr3", "units3", 42.5f);
 
   const MemoryAllocatorDump* sub_heap =
       pmd.GetAllocatorDump("foobar_allocator/sub_heap");
   ASSERT_NE(nullptr, sub_heap);
   EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
-  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);
-
+  CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize,
+              MemoryAllocatorDump::kUnitsBytes, 1);
+  CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectCount,
+              MemoryAllocatorDump::kUnitsObjects, 3);
   const MemoryAllocatorDump* empty_sub_heap =
       pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
   ASSERT_NE(nullptr, empty_sub_heap);
   EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
-  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));
+  auto raw_attrs = empty_sub_heap->attributes_for_testing()->ToBaseValue();
+  DictionaryValue* attrs = nullptr;
+  ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs));
+  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameSize));
+  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectCount));
 
   // Check that the AsValueInfo doesn't hit any DCHECK.
   scoped_refptr<TracedValue> traced_value(new TracedValue());
@@ -138,7 +172,7 @@
 #if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
 TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
   FakeMemoryAllocatorDumpProvider fmadp;
-  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+  ProcessMemoryDump pmd(new MemoryDumpSessionState(nullptr, nullptr));
   pmd.CreateAllocatorDump("foo_allocator");
   pmd.CreateAllocatorDump("bar_allocator/heap");
   ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 1e4d822..cbce210 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -5,9 +5,18 @@
 #include "base/trace_event/memory_dump_manager.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/atomic_sequence_num.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
 #include "base/compiler_specific.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/malloc_dump_provider.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/memory_dump_session_state.h"
 #include "base/trace_event/process_memory_dump.h"
@@ -19,7 +28,6 @@
 #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
 
@@ -36,106 +44,68 @@
 
 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();
-  }
-}
+uint32_t g_periodic_dumps_count = 0;
+uint32_t g_heavy_dumps_rate = 0;
+MemoryDumpManager* g_instance_for_testing = nullptr;
 
 void RequestPeriodicGlobalDump() {
+  MemoryDumpLevelOfDetail level_of_detail;
+  if (g_heavy_dumps_rate == 0) {
+    level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
+  } else {
+    level_of_detail = g_periodic_dumps_count == 0
+                          ? MemoryDumpLevelOfDetail::DETAILED
+                          : MemoryDumpLevelOfDetail::LIGHT;
+
+    if (++g_periodic_dumps_count == g_heavy_dumps_rate)
+      g_periodic_dumps_count = 0;
+  }
+
   MemoryDumpManager::GetInstance()->RequestGlobalDump(
-      MemoryDumpType::PERIODIC_INTERVAL);
+      MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
+}
+
+// Callback wrapper to hook upon the completion of RequestGlobalDump() and
+// inject trace markers.
+void OnGlobalDumpDone(MemoryDumpCallback wrapped_callback,
+                      uint64_t dump_guid,
+                      bool success) {
+  TRACE_EVENT_NESTABLE_ASYNC_END1(
+      MemoryDumpManager::kTraceCategory, "GlobalMemoryDump",
+      TRACE_ID_MANGLE(dump_guid), "success", success);
+
+  if (!wrapped_callback.is_null()) {
+    wrapped_callback.Run(dump_guid, success);
+    wrapped_callback.Reset();
+  }
 }
 
 }  // namespace
 
 // static
-const char* const MemoryDumpManager::kTraceCategoryForTesting = kTraceCategory;
+const char* const MemoryDumpManager::kTraceCategory =
+    TRACE_DISABLED_BY_DEFAULT("memory-infra");
+
+// static
+const int MemoryDumpManager::kMaxConsecutiveFailuresCount = 3;
+
+// static
+const uint64_t MemoryDumpManager::kInvalidTracingProcessId = 0;
+
+// static
+const char* const MemoryDumpManager::kSystemAllocatorPoolName =
+#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
+    MallocDumpProvider::kAllocatedObjects;
+#elif defined(OS_WIN)
+    WinHeapDumpProvider::kAllocatedObjects;
+#else
+    nullptr;
+#endif
 
 // static
 MemoryDumpManager* MemoryDumpManager::GetInstance() {
@@ -148,257 +118,542 @@
 
 // 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),
+      is_coordinator_(false),
       memory_tracing_enabled_(0),
-      skip_core_dumpers_auto_registration_for_testing_(false) {
+      tracing_process_id_(kInvalidTracingProcessId),
+      dumper_registrations_ignored_for_testing_(false) {
   g_next_guid.GetNext();  // Make sure that first guid is not zero.
+
+  heap_profiling_enabled_ = CommandLine::InitializedForCurrentProcess()
+                                ? CommandLine::ForCurrentProcess()->HasSwitch(
+                                      switches::kEnableHeapProfiling)
+                                : false;
+
+  if (heap_profiling_enabled_)
+    AllocationContextTracker::SetCaptureEnabled(true);
 }
 
 MemoryDumpManager::~MemoryDumpManager() {
-  base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
 }
 
-void MemoryDumpManager::Initialize() {
-  TRACE_EVENT0(kTraceCategory, "init");  // Add to trace-viewer category list.
-  trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
+void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate,
+                                   bool is_coordinator) {
+  {
+    AutoLock lock(lock_);
+    DCHECK(delegate);
+    DCHECK(!delegate_);
+    delegate_ = delegate;
+    is_coordinator_ = is_coordinator;
+  }
 
-  if (skip_core_dumpers_auto_registration_for_testing_)
-    return;
-
-  // Enable the core dump providers.
+// Enable the core dump providers.
 #if !defined(OS_NACL)
-  RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+  RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance(),
+                       "ProcessMemoryTotals", nullptr);
+#endif
+
+#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
+  RegisterDumpProvider(MallocDumpProvider::GetInstance(), "Malloc", nullptr);
 #endif
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
-  RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
-  RegisterDumpProvider(MallocDumpProvider::GetInstance());
+  RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance(),
+                       "ProcessMemoryMaps", nullptr);
 #endif
 
 #if defined(OS_ANDROID)
-  RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
+  RegisterDumpProvider(JavaHeapDumpProvider::GetInstance(), "JavaHeap",
+                       nullptr);
 #endif
 
 #if defined(OS_WIN)
-  RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
+  RegisterDumpProvider(WinHeapDumpProvider::GetInstance(), "WinHeap", nullptr);
 #endif
-}
 
-void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) {
-  AutoLock lock(lock_);
-  DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_);
-  delegate_ = delegate;
+  // If tracing was enabled before initializing MemoryDumpManager, we missed the
+  // OnTraceLogEnabled() event. Synthetize it so we can late-join the party.
+  bool is_tracing_already_enabled = TraceLog::GetInstance()->IsEnabled();
+  TRACE_EVENT0(kTraceCategory, "init");  // Add to trace-viewer category list.
+  TraceLog::GetInstance()->AddEnabledStateObserver(this);
+  if (is_tracing_already_enabled)
+    OnTraceLogEnabled();
 }
 
 void MemoryDumpManager::RegisterDumpProvider(
     MemoryDumpProvider* mdp,
-    const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
-  MemoryDumpProviderInfo mdp_info(task_runner);
+    const char* name,
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+    const MemoryDumpProvider::Options& options) {
+  if (dumper_registrations_ignored_for_testing_)
+    return;
+
+  MemoryDumpProviderInfo mdp_info(mdp, name, task_runner, options);
   AutoLock lock(lock_);
-  dump_providers_.insert(std::make_pair(mdp, mdp_info));
+  auto iter_new = dump_providers_.insert(mdp_info);
+
+  // If there was a previous entry, replace it with the new one. This is to deal
+  // with the case where a dump provider unregisters itself and then re-
+  // registers before a memory dump happens, so its entry was still in the
+  // collection but flagged |unregistered|.
+  if (!iter_new.second) {
+    dump_providers_.erase(iter_new.first);
+    dump_providers_.insert(mdp_info);
+  }
+
+  if (heap_profiling_enabled_)
+    mdp->OnHeapProfilingEnabled(true);
 }
 
-void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
-  RegisterDumpProvider(mdp, nullptr);
+void MemoryDumpManager::RegisterDumpProvider(
+    MemoryDumpProvider* mdp,
+    const char* name,
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+  RegisterDumpProvider(mdp, name, task_runner, MemoryDumpProvider::Options());
 }
 
 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
   AutoLock lock(lock_);
 
-  auto it = dump_providers_.find(mdp);
-  if (it == dump_providers_.end())
+  auto mdp_iter = dump_providers_.begin();
+  for (; mdp_iter != dump_providers_.end(); ++mdp_iter) {
+    if (mdp_iter->dump_provider == mdp)
+      break;
+  }
+
+  if (mdp_iter == dump_providers_.end())
     return;
 
-  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.";
+  DCHECK(!subtle::NoBarrier_Load(&memory_tracing_enabled_) ||
+         (mdp_iter->task_runner &&
+          mdp_iter->task_runner->BelongsToCurrentThread()))
+      << "MemoryDumpProvider \"" << mdp_iter->name << "\" 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);
+  mdp_iter->unregistered = true;
 }
 
 void MemoryDumpManager::RequestGlobalDump(
     MemoryDumpType dump_type,
+    MemoryDumpLevelOfDetail level_of_detail,
     const MemoryDumpCallback& callback) {
   // Bail out immediately if tracing is not enabled at all.
-  if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)))
+  if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_))) {
+    if (!callback.is_null())
+      callback.Run(0u /* guid */, false /* success */);
     return;
+  }
 
-  const uint64 guid =
+  const uint64_t 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.
+  // Creates an async event to keep track of the global dump evolution.
+  // The |wrapped_callback| will generate the ASYNC_END event and then invoke
+  // the real |callback| provided by the caller.
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "GlobalMemoryDump",
+                                    TRACE_ID_MANGLE(guid));
+  MemoryDumpCallback wrapped_callback = Bind(&OnGlobalDumpDone, callback);
+
+  // Technically there is no need to grab the |lock_| here as the delegate is
+  // long-lived and can only be set by Initialize(), which is locked and
+  // necessarily happens before memory_tracing_enabled_ == true.
+  // Not taking the |lock_|, though, is lakely make TSan barf and, at this point
+  // (memory-infra is enabled) we're not in the fast-path anymore.
   MemoryDumpManagerDelegate* delegate;
   {
     AutoLock lock(lock_);
     delegate = delegate_;
   }
 
-  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 */);
-  }
+  // The delegate will coordinate the IPC broadcast and at some point invoke
+  // CreateProcessDump() to get a dump for the current process.
+  MemoryDumpRequestArgs args = {guid, dump_type, level_of_detail};
+  delegate->RequestGlobalMemoryDump(args, wrapped_callback);
 }
 
-void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type) {
-  RequestGlobalDump(dump_type, MemoryDumpCallback());
+void MemoryDumpManager::RequestGlobalDump(
+    MemoryDumpType dump_type,
+    MemoryDumpLevelOfDetail level_of_detail) {
+  RequestGlobalDump(dump_type, level_of_detail, 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;
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump",
+                                    TRACE_ID_MANGLE(args.dump_guid));
 
-  // 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.
+  scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
   {
     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;
+    pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
+        args, dump_providers_.begin(), session_state_, callback,
+        dump_thread_->task_runner()));
   }
-  return dump_successful;
+
+  TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump",
+                         TRACE_ID_MANGLE(args.dump_guid),
+                         TRACE_EVENT_FLAG_FLOW_OUT);
+
+  // Start the thread hop. |dump_providers_| are kept sorted by thread, so
+  // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread
+  // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()).
+  ContinueAsyncProcessDump(std::move(pmd_async_state));
 }
 
-// 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.
+// At most one ContinueAsyncProcessDump() can be active at any time for a given
+// PMD, regardless of status of the |lock_|. |lock_| is used here purely to
+// ensure consistency w.r.t. (un)registrations of |dump_providers_|.
+// The linearization of dump providers' OnMemoryDump invocations is achieved by
+// means of subsequent PostTask(s).
+//
+// 1) Prologue:
+//   - Check if the dump provider is disabled, if so skip the dump.
+//   - Check if we are on the right thread. If not hop and continue there.
+// 2) Invoke the dump provider's OnMemoryDump() (unless skipped).
+// 3) Epilogue:
+//  - Unregister the dump provider if it failed too many times consecutively.
+//  - Advance the |next_dump_provider| iterator to the next dump provider.
+//  - If this was the last hop, create a trace event, add it to the trace
+//    and finalize (invoke callback).
+
 void MemoryDumpManager::ContinueAsyncProcessDump(
-    MemoryDumpProvider* mdp,
-    scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) {
-  bool should_finalize_dump = false;
+    scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
+  // Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
+  // in the PostTask below don't end up registering their own dump providers
+  // (for discounting trace memory overhead) while holding the |lock_|.
+  TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
+
+  const uint64_t dump_guid = pmd_async_state->req_args.dump_guid;
+  const char* dump_provider_name = nullptr;
+
+  // Pid of the target process being dumped. Often kNullProcessId (= current
+  // process), non-zero when the coordinator process creates dumps on behalf
+  // of child processes (see crbug.com/461788).
+  ProcessId pid;
+
+  // DO NOT put any LOG() statement in the locked sections, as in some contexts
+  // (GPU process) LOG() ends up performing PostTask/IPCs.
+  MemoryDumpProvider* mdp;
+  bool skip_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);
+    auto mdp_info = pmd_async_state->next_dump_provider;
+    mdp = mdp_info->dump_provider;
+    dump_provider_name = mdp_info->name;
+    pid = mdp_info->options.target_pid;
 
-    // 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;
+    // If the dump provider did not specify a thread affinity, dump on
+    // |dump_thread_|.
+    SingleThreadTaskRunner* task_runner = mdp_info->task_runner.get();
+    if (!task_runner)
+      task_runner = pmd_async_state->dump_thread_task_runner.get();
+
+    // |dump_thread_| might have been Stop()-ed at this point (if tracing was
+    // disabled in the meanwhile). In such case the PostTask() below will fail.
+    // |task_runner|, however, should always be non-null.
+    DCHECK(task_runner);
+
+    if (mdp_info->disabled || mdp_info->unregistered) {
+      skip_dump = true;
+    } else if (!task_runner->BelongsToCurrentThread()) {
+      // It's time to hop onto another thread.
+
+      // Copy the callback + arguments just for the unlikley case in which
+      // PostTask fails. In such case the Bind helper will destroy the
+      // pmd_async_state and we must keep a copy of the fields to notify the
+      // abort.
+      MemoryDumpCallback callback = pmd_async_state->callback;
+      scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
+          pmd_async_state->callback_task_runner;
+
+      const bool did_post_task = task_runner->PostTask(
+          FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
+                          Unretained(this), Passed(&pmd_async_state)));
+      if (did_post_task)
+        return;
+
+      // The thread is gone. At this point the best thing we can do is to
+      // disable the dump provider and abort this dump.
+      mdp_info->disabled = true;
+      return AbortDumpLocked(callback, callback_task_runner, dump_guid);
+    }
   }  // AutoLock(lock_)
 
-  if (should_finalize_dump)
-    FinalizeDumpAndAddToTrace(pmd_holder);
+  // Invoke the dump provider without holding the |lock_|.
+  bool finalize = false;
+  bool dump_successful = false;
+
+  if (!skip_dump) {
+    TRACE_EVENT_WITH_FLOW1(kTraceCategory,
+                           "MemoryDumpManager::ContinueAsyncProcessDump",
+                           TRACE_ID_MANGLE(dump_guid),
+                           TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+                           "dump_provider.name", dump_provider_name);
+    MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail};
+    ProcessMemoryDump* process_memory_dump =
+        pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(pid);
+    dump_successful = mdp->OnMemoryDump(args, process_memory_dump);
+  }
+
+  {
+    AutoLock lock(lock_);
+    auto mdp_info = pmd_async_state->next_dump_provider;
+    if (dump_successful) {
+      mdp_info->consecutive_failures = 0;
+    } else if (!skip_dump) {
+      ++mdp_info->consecutive_failures;
+      if (mdp_info->consecutive_failures >= kMaxConsecutiveFailuresCount) {
+        mdp_info->disabled = true;
+      }
+    }
+    ++pmd_async_state->next_dump_provider;
+    finalize = pmd_async_state->next_dump_provider == dump_providers_.end();
+
+    if (mdp_info->unregistered)
+      dump_providers_.erase(mdp_info);
+  }
+
+  if (!skip_dump && !dump_successful) {
+    LOG(ERROR) << "MemoryDumpProvider \"" << dump_provider_name << "\" failed, "
+               << "possibly due to sandboxing (crbug.com/461788)."
+               << "Disabling dumper for current process. Try --no-sandbox.";
+  }
+
+  if (finalize)
+    return FinalizeDumpAndAddToTrace(std::move(pmd_async_state));
+
+  ContinueAsyncProcessDump(std::move(pmd_async_state));
 }
 
-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;
+// static
+void MemoryDumpManager::FinalizeDumpAndAddToTrace(
+    scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
+  const uint64_t dump_guid = pmd_async_state->req_args.dump_guid;
+  if (!pmd_async_state->callback_task_runner->BelongsToCurrentThread()) {
+    scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
+        pmd_async_state->callback_task_runner;
+    callback_task_runner->PostTask(
+        FROM_HERE, Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace,
+                        Passed(&pmd_async_state)));
     return;
   }
 
-  session_state_ = new MemoryDumpSessionState();
-  for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
-    it->second.disabled = false;
+  TRACE_EVENT_WITH_FLOW0(kTraceCategory,
+                         "MemoryDumpManager::FinalizeDumpAndAddToTrace",
+                         TRACE_ID_MANGLE(dump_guid), TRACE_EVENT_FLAG_FLOW_IN);
+
+  for (const auto& kv : pmd_async_state->process_dumps) {
+    ProcessId pid = kv.first;  // kNullProcessId for the current process.
+    ProcessMemoryDump* process_memory_dump = kv.second.get();
+    TracedValue* traced_value = new TracedValue();
+    scoped_refptr<ConvertableToTraceFormat> event_value(traced_value);
+    process_memory_dump->AsValueInto(traced_value);
+    traced_value->SetString("level_of_detail",
+                            MemoryDumpLevelOfDetailToString(
+                                pmd_async_state->req_args.level_of_detail));
+    const char* const event_name =
+        MemoryDumpTypeToString(pmd_async_state->req_args.dump_type);
+
+    TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
+        TRACE_EVENT_PHASE_MEMORY_DUMP,
+        TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
+        dump_guid, pid, kTraceEventNumArgs, kTraceEventArgNames,
+        kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
+        TRACE_EVENT_FLAG_HAS_ID);
+  }
+
+  if (!pmd_async_state->callback.is_null()) {
+    pmd_async_state->callback.Run(dump_guid, true /* success */);
+    pmd_async_state->callback.Reset();
+  }
+
+  TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump",
+                                  TRACE_ID_MANGLE(dump_guid));
+}
+
+// static
+void MemoryDumpManager::AbortDumpLocked(
+    MemoryDumpCallback callback,
+    scoped_refptr<SingleThreadTaskRunner> task_runner,
+    uint64_t dump_guid) {
+  if (callback.is_null())
+    return;  // There is nothing to NACK.
+
+  // Post the callback even if we are already on the right thread to avoid
+  // invoking the callback while holding the lock_.
+  task_runner->PostTask(FROM_HERE,
+                        Bind(callback, dump_guid, false /* success */));
+}
+
+void MemoryDumpManager::OnTraceLogEnabled() {
+  bool enabled;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
+  if (!enabled)
+    return;
+
+  // Initialize the TraceLog for the current thread. This is to avoid that the
+  // TraceLog memory dump provider is registered lazily in the PostTask() below
+  // while the |lock_| is taken;
+  TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
+
+  // Spin-up the thread used to invoke unbound dump providers.
+  scoped_ptr<Thread> dump_thread(new Thread("MemoryInfra"));
+  if (!dump_thread->Start()) {
+    LOG(ERROR) << "Failed to start the memory-infra thread for tracing";
+    return;
+  }
+
+  AutoLock lock(lock_);
+
+  DCHECK(delegate_);  // At this point we must have a delegate.
+
+  scoped_refptr<StackFrameDeduplicator> stack_frame_deduplicator = nullptr;
+  scoped_refptr<TypeNameDeduplicator> type_name_deduplicator = nullptr;
+
+  if (heap_profiling_enabled_) {
+    // If heap profiling is enabled, the stack frame deduplicator and type name
+    // deduplicator will be in use. Add a metadata events to write the frames
+    // and type IDs.
+    stack_frame_deduplicator = new StackFrameDeduplicator;
+    type_name_deduplicator = new TypeNameDeduplicator;
+    TRACE_EVENT_API_ADD_METADATA_EVENT(
+        "stackFrames", "stackFrames",
+        scoped_refptr<ConvertableToTraceFormat>(stack_frame_deduplicator));
+    TRACE_EVENT_API_ADD_METADATA_EVENT(
+        "typeNames", "typeNames",
+        scoped_refptr<ConvertableToTraceFormat>(type_name_deduplicator));
+  }
+
+  DCHECK(!dump_thread_);
+  dump_thread_ = std::move(dump_thread);
+  session_state_ = new MemoryDumpSessionState(stack_frame_deduplicator,
+                                              type_name_deduplicator);
+
+  for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
+    it->disabled = false;
+    it->consecutive_failures = 0;
+  }
 
   subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
 
-  if (delegate_->IsCoordinatorProcess()) {
-    periodic_dump_timer_.Start(FROM_HERE,
-                               TimeDelta::FromSeconds(kDumpIntervalSeconds),
-                               base::Bind(&RequestPeriodicGlobalDump));
+  // TODO(primiano): This is a temporary hack to disable periodic memory dumps
+  // when running memory benchmarks until telemetry uses TraceConfig to
+  // enable/disable periodic dumps. See crbug.com/529184 .
+  if (!is_coordinator_ ||
+      CommandLine::ForCurrentProcess()->HasSwitch(
+          "enable-memory-benchmarking")) {
+    return;
   }
+
+  // Enable periodic dumps. At the moment the periodic support is limited to at
+  // most one low-detail periodic dump and at most one high-detail periodic
+  // dump. If both are specified the high-detail period must be an integer
+  // multiple of the low-level one.
+  g_periodic_dumps_count = 0;
+  const TraceConfig trace_config =
+      TraceLog::GetInstance()->GetCurrentTraceConfig();
+  const TraceConfig::MemoryDumpConfig& config_list =
+      trace_config.memory_dump_config();
+  if (config_list.empty())
+    return;
+
+  uint32_t min_timer_period_ms = std::numeric_limits<uint32_t>::max();
+  uint32_t heavy_dump_period_ms = 0;
+  DCHECK_LE(config_list.size(), 2u);
+  for (const TraceConfig::MemoryDumpTriggerConfig& config : config_list) {
+    DCHECK(config.periodic_interval_ms);
+    if (config.level_of_detail == MemoryDumpLevelOfDetail::DETAILED)
+      heavy_dump_period_ms = config.periodic_interval_ms;
+    min_timer_period_ms =
+        std::min(min_timer_period_ms, config.periodic_interval_ms);
+  }
+  DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms);
+  g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms;
+
+  periodic_dump_timer_.Start(FROM_HERE,
+                             TimeDelta::FromMilliseconds(min_timer_period_ms),
+                             base::Bind(&RequestPeriodicGlobalDump));
 }
 
 void MemoryDumpManager::OnTraceLogDisabled() {
-  AutoLock lock(lock_);
-  periodic_dump_timer_.Stop();
   subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
-  session_state_ = nullptr;
+  scoped_ptr<Thread> dump_thread;
+  {
+    AutoLock lock(lock_);
+    dump_thread = std::move(dump_thread_);
+    session_state_ = nullptr;
+  }
+
+  // Thread stops are blocking and must be performed outside of the |lock_|
+  // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it).
+  periodic_dump_timer_.Stop();
+  if (dump_thread)
+    dump_thread->Stop();
+}
+
+uint64_t MemoryDumpManager::GetTracingProcessId() const {
+  return delegate_->GetTracingProcessId();
 }
 
 MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
-    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
-    : task_runner(task_runner), disabled(false) {
+    MemoryDumpProvider* dump_provider,
+    const char* name,
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+    const MemoryDumpProvider::Options& options)
+    : dump_provider(dump_provider),
+      name(name),
+      task_runner(task_runner),
+      options(options),
+      consecutive_failures(0),
+      disabled(false),
+      unregistered(false) {}
+
+MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {}
+
+bool MemoryDumpManager::MemoryDumpProviderInfo::operator<(
+    const MemoryDumpProviderInfo& other) const {
+  if (task_runner == other.task_runner)
+    return dump_provider < other.dump_provider;
+  // Ensure that unbound providers (task_runner == nullptr) always run last.
+  return !(task_runner < other.task_runner);
 }
-MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
+
+MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
+    MemoryDumpRequestArgs req_args,
+    MemoryDumpProviderInfoSet::iterator next_dump_provider,
+    const scoped_refptr<MemoryDumpSessionState>& session_state,
+    MemoryDumpCallback callback,
+    const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner)
+    : req_args(req_args),
+      next_dump_provider(next_dump_provider),
+      session_state(session_state),
+      callback(callback),
+      callback_task_runner(MessageLoop::current()->task_runner()),
+      dump_thread_task_runner(dump_thread_task_runner) {}
+
+MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() {
+}
+
+ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState::
+    GetOrCreateMemoryDumpContainerForProcess(ProcessId pid) {
+  auto iter = process_dumps.find(pid);
+  if (iter == process_dumps.end()) {
+    scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state));
+    iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first;
+  }
+  return iter->second.get();
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 3645ac1..a5037cf 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -5,7 +5,9 @@
 #ifndef BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
 #define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
 
-#include <vector>
+#include <map>
+#include <memory>
+#include <set>
 
 #include "base/atomicops.h"
 #include "base/containers/hash_tables.h"
@@ -14,21 +16,18 @@
 #include "base/synchronization/lock.h"
 #include "base/timer/timer.h"
 #include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
 
 namespace base {
 
 class SingleThreadTaskRunner;
+class Thread;
 
 namespace trace_event {
 
-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
@@ -36,26 +35,49 @@
 // RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
 class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
  public:
-  static const char* const kTraceCategoryForTesting;
+  static const char* const kTraceCategory;
+
+  // This value is returned as the tracing id of the child processes by
+  // GetTracingProcessId() when tracing is not enabled.
+  static const uint64_t kInvalidTracingProcessId;
 
   static MemoryDumpManager* GetInstance();
 
-  // Invoked once per process to register the TraceLog observer.
-  void Initialize();
+  // Invoked once per process to listen to trace begin / end events.
+  // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls
+  // and the MemoryDumpManager guarantees to support this.
+  // On the other side, the MemoryDumpManager will not be fully operational
+  // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized.
+  // Arguments:
+  //  is_coordinator: if true this MemoryDumpManager instance will act as a
+  //      coordinator and schedule periodic dumps (if enabled via TraceConfig);
+  //      false when the MemoryDumpManager is initialized in a slave process.
+  //  delegate: inversion-of-control interface for embedder-specific behaviors
+  //      (multiprocess handshaking). See the lifetime and thread-safety
+  //      requirements in the |MemoryDumpManagerDelegate| docstring.
+  void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator);
 
-  // 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.
+  // (Un)Registers a MemoryDumpProvider instance.
+  // Args:
+  //  - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager
+  //      does NOT take memory ownership of |mdp|, which is expected to either
+  //      be a singleton or unregister itself.
+  //  - name: a friendly name (duplicates allowed). Used for debugging and
+  //      run-time profiling of memory-infra internals. Must be a long-lived
+  //      C string.
+  //  - task_runner: if non-null, all the calls to |mdp| will be
+  //      issued on the given thread. Otherwise, |mdp| should be able to
+  //      handle calls on arbitrary threads.
+  //  - options: extra optional arguments. See memory_dump_provider.h.
   void RegisterDumpProvider(
       MemoryDumpProvider* mdp,
+      const char* name,
       const scoped_refptr<SingleThreadTaskRunner>& task_runner);
-  void RegisterDumpProvider(MemoryDumpProvider* mdp);
+  void RegisterDumpProvider(
+      MemoryDumpProvider* mdp,
+      const char* name,
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+      const MemoryDumpProvider::Options& options);
   void UnregisterDumpProvider(MemoryDumpProvider* mdp);
 
   // Requests a memory dump. The dump might happen or not depending on the
@@ -65,10 +87,12 @@
   // processes have dumped) and its success (true iff all the dumps were
   // successful).
   void RequestGlobalDump(MemoryDumpType dump_type,
+                         MemoryDumpLevelOfDetail level_of_detail,
                          const MemoryDumpCallback& callback);
 
   // Same as above (still asynchronous), but without callback.
-  void RequestGlobalDump(MemoryDumpType dump_type);
+  void RequestGlobalDump(MemoryDumpType dump_type,
+                         MemoryDumpLevelOfDetail level_of_detail);
 
   // TraceLog::EnabledStateObserver implementation.
   void OnTraceLogEnabled() override;
@@ -81,27 +105,130 @@
     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();
+  // Returns a unique id for identifying the processes. The id can be
+  // retrieved by child processes only when tracing is enabled. This is
+  // intended to express cross-process sharing of memory dumps on the
+  // child-process side, without having to know its own child process id.
+  uint64_t GetTracingProcessId() const;
 
-    scoped_refptr<SingleThreadTaskRunner> task_runner;  // Optional.
-    bool disabled;  // For fail-safe logic (auto-disable failing MDPs).
+  // Returns the name for a the allocated_objects dump. Use this to declare
+  // suballocator dumps from other dump providers.
+  // It will return nullptr if there is no dump provider for the system
+  // allocator registered (which is currently the case for Mac OS).
+  const char* system_allocator_pool_name() const {
+    return kSystemAllocatorPoolName;
   };
 
-  friend struct DefaultDeleter<MemoryDumpManager>;  // For the testing instance.
+  // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
+  void set_dumper_registrations_ignored_for_testing(bool ignored) {
+    dumper_registrations_ignored_for_testing_ = ignored;
+  }
+
+ private:
+  friend std::default_delete<MemoryDumpManager>;  // For the testing instance.
   friend struct DefaultSingletonTraits<MemoryDumpManager>;
   friend class MemoryDumpManagerDelegate;
   friend class MemoryDumpManagerTest;
 
-  static void SetInstanceForTesting(MemoryDumpManager* instance);
+  // Descriptor struct used to hold information about registered MDPs. It is
+  // deliberately copyable, in order to allow it to be used as std::set value.
+  struct MemoryDumpProviderInfo {
+    MemoryDumpProviderInfo(
+        MemoryDumpProvider* dump_provider,
+        const char* name,
+        const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+        const MemoryDumpProvider::Options& options);
+    ~MemoryDumpProviderInfo();
+
+    // Define a total order based on the thread (i.e. |task_runner|) affinity,
+    // so that all MDP belonging to the same thread are adjacent in the set.
+    bool operator<(const MemoryDumpProviderInfo& other) const;
+
+    MemoryDumpProvider* const dump_provider;
+    const char* const name;
+
+    // The task_runner affinity. Can be nullptr, in which case the dump provider
+    // will be invoked on |dump_thread_|.
+    scoped_refptr<SingleThreadTaskRunner> task_runner;
+
+    // The |options| arg passed to RegisterDumpProvider().
+    const MemoryDumpProvider::Options options;
+
+    // For fail-safe logic (auto-disable failing MDPs). These fields are mutable
+    // as can be safely changed without impacting the order within the set.
+    mutable int consecutive_failures;
+    mutable bool disabled;
+
+    // When a dump provider unregisters, it is flagged as |unregistered| and it
+    // is removed only upon the next memory dump. This is to avoid altering the
+    // |dump_providers_| collection while a dump is in progress.
+    mutable bool unregistered;
+  };
+
+  using MemoryDumpProviderInfoSet = std::set<MemoryDumpProviderInfo>;
+
+  // Holds the state of a process memory dump that needs to be carried over
+  // across threads in order to fulfil an asynchronous CreateProcessDump()
+  // request. At any time exactly one thread owns a ProcessMemoryDumpAsyncState.
+  struct ProcessMemoryDumpAsyncState {
+    ProcessMemoryDumpAsyncState(
+        MemoryDumpRequestArgs req_args,
+        MemoryDumpProviderInfoSet::iterator next_dump_provider,
+        const scoped_refptr<MemoryDumpSessionState>& session_state,
+        MemoryDumpCallback callback,
+        const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner);
+    ~ProcessMemoryDumpAsyncState();
+
+    // Gets or creates the memory dump container for the given target process.
+    ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess(ProcessId pid);
+
+    // A map of ProcessId -> ProcessMemoryDump, one for each target process
+    // being dumped from the current process. Typically each process dumps only
+    // for itself, unless dump providers specify a different |target_process| in
+    // MemoryDumpProvider::Options.
+    std::map<ProcessId, scoped_ptr<ProcessMemoryDump>> process_dumps;
+
+    // The arguments passed to the initial CreateProcessDump() request.
+    const MemoryDumpRequestArgs req_args;
+
+    // The |dump_providers_| iterator to the next dump provider that should be
+    // invoked (or dump_providers_.end() if at the end of the sequence).
+    MemoryDumpProviderInfoSet::iterator next_dump_provider;
+
+    // The trace-global session state.
+    scoped_refptr<MemoryDumpSessionState> session_state;
+
+    // Callback passed to the initial call to CreateProcessDump().
+    MemoryDumpCallback callback;
+
+    // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
+    // should be invoked. This is the thread on which the initial
+    // CreateProcessDump() request was called.
+    const scoped_refptr<SingleThreadTaskRunner> callback_task_runner;
+
+    // The thread on which unbound dump providers should be invoked.
+    // This is essentially |dump_thread_|.task_runner() but needs to be kept
+    // as a separate variable as it needs to be accessed by arbitrary dumpers'
+    // threads outside of the lock_ to avoid races when disabling tracing.
+    // It is immutable for all the duration of a tracing session.
+    const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
+  };
+
+  static const int kMaxConsecutiveFailuresCount;
+  static const char* const kSystemAllocatorPoolName;
 
   MemoryDumpManager();
-  virtual ~MemoryDumpManager();
+  ~MemoryDumpManager() override;
+
+  static void SetInstanceForTesting(MemoryDumpManager* instance);
+  static void FinalizeDumpAndAddToTrace(
+      scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
+  static void AbortDumpLocked(MemoryDumpCallback callback,
+                              scoped_refptr<SingleThreadTaskRunner> task_runner,
+                              uint64_t dump_guid);
 
   // Internal, used only by MemoryDumpManagerDelegate.
   // Creates a memory dump for the current process and appends it to the trace.
@@ -110,19 +237,23 @@
   void CreateProcessDump(const MemoryDumpRequestArgs& args,
                          const MemoryDumpCallback& callback);
 
-  bool InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
-                                ProcessMemoryDump* pmd);
+  // Continues the ProcessMemoryDump started by CreateProcessDump(), hopping
+  // across threads as needed as specified by MDPs in RegisterDumpProvider().
   void ContinueAsyncProcessDump(
-      MemoryDumpProvider* mdp,
-      scoped_refptr<ProcessMemoryDumpHolder> pmd_holder);
+      scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
 
-  hash_map<MemoryDumpProvider*, MemoryDumpProviderInfo> dump_providers_;
+  // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by thread
+  // affinity (MDPs belonging to the same thread are adjacent).
+  MemoryDumpProviderInfoSet dump_providers_;
 
   // Shared among all the PMDs to keep state scoped to the tracing session.
   scoped_refptr<MemoryDumpSessionState> session_state_;
 
   MemoryDumpManagerDelegate* delegate_;  // Not owned.
 
+  // When true, this instance is in charge of coordinating periodic dumps.
+  bool is_coordinator_;
+
   // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
   // to guard against disabling logging while dumping on another thread.
   Lock lock_;
@@ -132,10 +263,20 @@
   subtle::AtomicWord memory_tracing_enabled_;
 
   // For time-triggered periodic dumps.
-  RepeatingTimer<MemoryDumpManager> periodic_dump_timer_;
+  RepeatingTimer periodic_dump_timer_;
 
-  // Skips the auto-registration of the core dumpers during Initialize().
-  bool skip_core_dumpers_auto_registration_for_testing_;
+  // Thread used for MemoryDumpProviders which don't specify a thread affinity.
+  scoped_ptr<Thread> dump_thread_;
+
+  // The unique id of the child process. This is created only for tracing and is
+  // expected to be valid only when tracing is enabled.
+  uint64_t tracing_process_id_;
+
+  // When true, calling |RegisterMemoryDumpProvider| is a no-op.
+  bool dumper_registrations_ignored_for_testing_;
+
+  // Whether new memory dump providers should be told to enable heap profiling.
+  bool heap_profiling_enabled_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
 };
@@ -147,9 +288,9 @@
   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;
+  // Returns tracing process id of the current process. This is used by
+  // MemoryDumpManager::GetTracingProcessId.
+  virtual uint64_t GetTracingProcessId() const = 0;
 
  protected:
   MemoryDumpManagerDelegate() {}
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 1da9429..34c98b0 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -8,227 +8,398 @@
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_io_thread.h"
+#include "base/test/trace_event_analyzer.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_config_memory_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
+using testing::AnyNumber;
+using testing::AtMost;
+using testing::Between;
 using testing::Invoke;
 using testing::Return;
 
 namespace base {
 namespace trace_event {
 
-// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
-// instead of performing IPC dances.
+// GTest matchers for MemoryDumpRequestArgs arguments.
+MATCHER(IsDetailedDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
+}
+
+MATCHER(IsLightDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
+}
+
+namespace {
+
+void RegisterDumpProvider(
+    MemoryDumpProvider* mdp,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    const MemoryDumpProvider::Options& options) {
+  MemoryDumpManager* mdm = MemoryDumpManager::GetInstance();
+  mdm->set_dumper_registrations_ignored_for_testing(false);
+  mdm->RegisterDumpProvider(mdp, "TestDumpProvider", task_runner, options);
+  mdm->set_dumper_registrations_ignored_for_testing(true);
+}
+
+void RegisterDumpProvider(MemoryDumpProvider* mdp) {
+  RegisterDumpProvider(mdp, nullptr, MemoryDumpProvider::Options());
+}
+
+void OnTraceDataCollected(Closure quit_closure,
+                          trace_event::TraceResultBuffer* buffer,
+                          const scoped_refptr<RefCountedString>& json,
+                          bool has_more_events) {
+  buffer->AddFragment(json->data());
+  if (!has_more_events)
+    quit_closure.Run();
+}
+
+}  // namespace
+
+// Testing MemoryDumpManagerDelegate which, by default, short-circuits dump
+// requests locally to the MemoryDumpManager instead of performing IPC dances.
 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
  public:
-  void RequestGlobalMemoryDump(
-      const base::trace_event::MemoryDumpRequestArgs& args,
-      const MemoryDumpCallback& callback) override {
-    CreateProcessDump(args, callback);
+  MemoryDumpManagerDelegateForTesting() {
+    ON_CALL(*this, RequestGlobalMemoryDump(_, _))
+        .WillByDefault(Invoke(
+            this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump));
   }
 
-  bool IsCoordinatorProcess() const override { return false; }
+  MOCK_METHOD2(RequestGlobalMemoryDump,
+               void(const MemoryDumpRequestArgs& args,
+                    const MemoryDumpCallback& callback));
+
+  uint64 GetTracingProcessId() const override {
+    NOTREACHED();
+    return MemoryDumpManager::kInvalidTracingProcessId;
+  }
+};
+
+class MockMemoryDumpProvider : public MemoryDumpProvider {
+ public:
+  MOCK_METHOD2(OnMemoryDump,
+               bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
 };
 
 class MemoryDumpManagerTest : public testing::Test {
  public:
+  MemoryDumpManagerTest() : testing::Test(), kDefaultOptions() {}
+
   void SetUp() override {
+    last_callback_success_ = false;
     message_loop_.reset(new MessageLoop());
     mdm_.reset(new MemoryDumpManager());
     MemoryDumpManager::SetInstanceForTesting(mdm_.get());
-    ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
-    MemoryDumpManager::GetInstance()->Initialize();
-    MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
+    ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance());
+    delegate_.reset(new MemoryDumpManagerDelegateForTesting);
   }
 
   void TearDown() override {
     MemoryDumpManager::SetInstanceForTesting(nullptr);
     mdm_.reset();
+    delegate_.reset();
     message_loop_.reset();
     TraceLog::DeleteForTesting();
   }
 
+  // Turns a Closure into a MemoryDumpCallback, keeping track of the callback
+  // result and taking care of posting the closure on the correct task runner.
   void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
                            Closure closure,
                            uint64 dump_guid,
                            bool success) {
+    last_callback_success_ = success;
     task_runner->PostTask(FROM_HERE, closure);
   }
 
  protected:
-  const char* kTraceCategory = MemoryDumpManager::kTraceCategoryForTesting;
+  void InitializeMemoryDumpManager(bool is_coordinator) {
+    mdm_->set_dumper_registrations_ignored_for_testing(true);
+    mdm_->Initialize(delegate_.get(), is_coordinator);
+  }
 
-  void EnableTracing(const char* category) {
-    TraceLog::GetInstance()->SetEnabled(
-        CategoryFilter(category), TraceLog::RECORDING_MODE, TraceOptions());
+  void RequestGlobalDumpAndWait(MemoryDumpType dump_type,
+                                MemoryDumpLevelOfDetail level_of_detail) {
+    RunLoop run_loop;
+    MemoryDumpCallback callback =
+        Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+             MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+    mdm_->RequestGlobalDump(dump_type, level_of_detail, callback);
+    run_loop.Run();
+  }
+
+  void EnableTracingWithLegacyCategories(const char* category) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""),
+                                        TraceLog::RECORDING_MODE);
+  }
+
+  void EnableTracingWithTraceConfig(const std::string& trace_config) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config),
+                                        TraceLog::RECORDING_MODE);
   }
 
   void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
 
+  bool IsPeriodicDumpingEnabled() const {
+    return mdm_->periodic_dump_timer_.IsRunning();
+  }
+
+  int GetMaxConsecutiveFailuresCount() const {
+    return MemoryDumpManager::kMaxConsecutiveFailuresCount;
+  }
+
+  const MemoryDumpProvider::Options kDefaultOptions;
   scoped_ptr<MemoryDumpManager> mdm_;
+  scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate_;
+  bool last_callback_success_;
 
  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_;
-};
-
+// Basic sanity checks. Registers a memory dump provider and checks that it is
+// called, but only when memory-infra is enabled.
 TEST_F(MemoryDumpManagerTest, SingleDumper) {
-  MockDumpProvider mdp;
-  mdm_->RegisterDumpProvider(&mdp);
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp;
+  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);
+  EnableTracingWithLegacyCategories("foobar-but-not-memory");
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
 
   // Now repeat enabling the memory category and check that the dumper is
   // invoked this time.
-  EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(3).WillRepeatedly(Return(true));
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true));
   for (int i = 0; i < 3; ++i)
-    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
   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();
+  // Finally check the unregister logic: the delegate will be invoked but not
+  // the dump provider, as it has been unregistered.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
 }
 
+// Checks that requesting dumps with high level of detail actually propagates
+// the level of the detail properly to OnMemoryDump() call on dump providers.
+TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp;
+
+  RegisterDumpProvider(&mdp);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)).WillOnce(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  // Check that requesting dumps with low level of detail actually propagates to
+  // OnMemoryDump() call on dump providers.
+  RegisterDumpProvider(&mdp);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)).WillOnce(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::LIGHT);
+  DisableTracing();
+  mdm_->UnregisterDumpProvider(&mdp);
+}
+
+// Checks that the SharedSessionState object is acqually shared over time.
 TEST_F(MemoryDumpManagerTest, SharedSessionState) {
-  MockDumpProvider mdp1;
-  MockDumpProvider mdp2;
-  mdm_->RegisterDumpProvider(&mdp1);
-  mdm_->RegisterDumpProvider(&mdp2);
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
+  RegisterDumpProvider(&mdp1);
+  RegisterDumpProvider(&mdp2);
 
-  EnableTracing(kTraceCategory);
-  EXPECT_CALL(mdp1, OnMemoryDump(_))
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  const MemoryDumpSessionState* session_state = mdm_->session_state().get();
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _))
       .Times(2)
-      .WillRepeatedly(
-          Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
-  EXPECT_CALL(mdp2, OnMemoryDump(_))
+      .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
+                                             ProcessMemoryDump* pmd) -> bool {
+        EXPECT_EQ(session_state, pmd->session_state().get());
+        return true;
+      }));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _))
       .Times(2)
-      .WillRepeatedly(
-          Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+      .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
+                                             ProcessMemoryDump* pmd) -> bool {
+        EXPECT_EQ(session_state, pmd->session_state().get());
+        return true;
+      }));
 
-  for (int i = 0; i < 2; ++i)
-    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  for (int i = 0; i < 2; ++i) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
 
   DisableTracing();
 }
 
+// Checks that the (Un)RegisterDumpProvider logic behaves sanely.
 TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
-  MockDumpProvider mdp1;
-  MockDumpProvider mdp2;
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider 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);
+  RegisterDumpProvider(&mdp1);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
 
   // Invert: enable mdp1 and disable mdp2.
   mdm_->UnregisterDumpProvider(&mdp1);
-  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);
+  RegisterDumpProvider(&mdp2);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
 
   // Enable both mdp1 and mdp2.
-  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);
+  RegisterDumpProvider(&mdp1);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
   DisableTracing();
 }
 
+// Checks that the dump provider invocations depend only on the current
+// registration state and not on previous registrations and dumps.
+TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp;
+
+  RegisterDumpProvider(&mdp);
+
+  {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    DisableTracing();
+  }
+
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    DisableTracing();
+  }
+
+  RegisterDumpProvider(&mdp);
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    DisableTracing();
+  }
+
+  RegisterDumpProvider(&mdp);
+  mdm_->UnregisterDumpProvider(&mdp);
+  RegisterDumpProvider(&mdp);
+
+  {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    DisableTracing();
+  }
+}
+
 // Checks that the MemoryDumpManager respects the thread affinity when a
 // MemoryDumpProvider specifies a task_runner(). The test starts creating 8
 // threads and registering a MemoryDumpProvider on each of them. At each
 // iteration, one thread is removed, to check the live unregistration logic.
 TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
   const uint32 kNumInitialThreads = 8;
 
-  ScopedVector<Thread> threads;
-  ScopedVector<MockDumpProvider> mdps;
+  std::vector<scoped_ptr<Thread>> threads;
+  std::vector<scoped_ptr<MockMemoryDumpProvider>> mdps;
 
   // Create the threads and setup the expectations. Given that at each iteration
   // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
   // invoked a number of times equal to its index.
   for (uint32 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(_))
+    threads.push_back(make_scoped_ptr(new Thread("test thread")));
+    auto thread = threads.back().get();
+    thread->Start();
+    scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner();
+    mdps.push_back(make_scoped_ptr(new MockMemoryDumpProvider()));
+    auto mdp = mdps.back().get();
+    RegisterDumpProvider(mdp, task_runner, kDefaultOptions);
+    EXPECT_CALL(*mdp, OnMemoryDump(_, _))
         .Times(i)
-        .WillRepeatedly(
-            Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
+        .WillRepeatedly(Invoke(
+            [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+              EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
+              return true;
+            }));
   }
-
-  EnableTracing(kTraceCategory);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::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();
-    }
+    last_callback_success_ = false;
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    EXPECT_TRUE(last_callback_success_);
 
     // Unregister a MDP and destroy one thread at each iteration to check the
     // live unregistration logic. The unregistration needs to happen on the same
@@ -237,7 +408,7 @@
       RunLoop run_loop;
       Closure unregistration =
           Bind(&MemoryDumpManager::UnregisterDumpProvider,
-               Unretained(mdm_.get()), Unretained(mdps.back()));
+               Unretained(mdm_.get()), Unretained(mdps.back().get()));
       threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
                                                       run_loop.QuitClosure());
       run_loop.Run();
@@ -250,27 +421,406 @@
   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.
+// Checks that providers get disabled after 3 consecutive failures, but not
+// otherwise (e.g., if interleaved).
 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
-  MockDumpProvider mdp1;
-  MockDumpProvider mdp2;
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
 
-  mdm_->RegisterDumpProvider(&mdp1);
-  mdm_->RegisterDumpProvider(&mdp2);
-  EnableTracing(kTraceCategory);
+  RegisterDumpProvider(&mdp1);
+  RegisterDumpProvider(&mdp2);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
 
-  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
-  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
-  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(kNumDumps);
 
-  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
-  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
-  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+      .Times(GetMaxConsecutiveFailuresCount())
+      .WillRepeatedly(Return(false));
+
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+      .WillOnce(Return(false))
+      .WillOnce(Return(true))
+      .WillOnce(Return(false))
+      .WillOnce(Return(false))
+      .WillOnce(Return(true))
+      .WillOnce(Return(false));
+
+  for (int i = 0; i < kNumDumps; i++) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
 
   DisableTracing();
 }
 
+// Sneakily registers an extra memory dump provider while an existing one is
+// dumping and expect it to take part in the already active tracing session.
+TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
+
+  RegisterDumpProvider(&mdp1);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+      .Times(4)
+      .WillOnce(Return(true))
+      .WillOnce(
+          Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+            RegisterDumpProvider(&mdp2);
+            return true;
+          }))
+      .WillRepeatedly(Return(true));
+
+  // Depending on the insertion order (before or after mdp1), mdp2 might be
+  // called also immediately after it gets registered.
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+      .Times(Between(2, 3))
+      .WillRepeatedly(Return(true));
+
+  for (int i = 0; i < 4; i++) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
+
+  DisableTracing();
+}
+
+// Like RegisterDumperWhileDumping, but unregister the dump provider instead.
+TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
+
+  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
+  RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+      .Times(4)
+      .WillOnce(Return(true))
+      .WillOnce(
+          Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+            MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2);
+            return true;
+          }))
+      .WillRepeatedly(Return(true));
+
+  // Depending on the insertion order (before or after mdp1), mdp2 might have
+  // been already called when UnregisterDumpProvider happens.
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+      .Times(Between(1, 2))
+      .WillRepeatedly(Return(true));
+
+  for (int i = 0; i < 4; i++) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
+
+  DisableTracing();
+}
+
+// Checks that the dump does not abort when unregistering a provider while
+// dumping from a different thread than the dumping thread.
+TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  ScopedVector<TestIOThread> threads;
+  ScopedVector<MockMemoryDumpProvider> mdps;
+
+  for (int i = 0; i < 2; i++) {
+    threads.push_back(new TestIOThread(TestIOThread::kAutoStart));
+    mdps.push_back(new MockMemoryDumpProvider());
+    RegisterDumpProvider(mdps.back(), threads.back()->task_runner(),
+                         kDefaultOptions);
+  }
+
+  int on_memory_dump_call_count = 0;
+
+  // When OnMemoryDump is called on either of the dump providers, it will
+  // unregister the other one.
+  for (MockMemoryDumpProvider* mdp : mdps) {
+    int other_idx = (mdps.front() == mdp);
+    TestIOThread* other_thread = threads[other_idx];
+    MockMemoryDumpProvider* other_mdp = mdps[other_idx];
+    auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count](
+        const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
+      other_thread->PostTaskAndWait(
+          FROM_HERE, base::Bind(&MemoryDumpManager::UnregisterDumpProvider,
+                                base::Unretained(&*mdm_), other_mdp));
+      on_memory_dump_call_count++;
+      return true;
+    };
+
+    // OnMemoryDump is called once for the provider that dumps first, and zero
+    // times for the other provider.
+    EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+        .Times(AtMost(1))
+        .WillOnce(Invoke(on_dump));
+  }
+
+  last_callback_success_ = false;
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  ASSERT_EQ(1, on_memory_dump_call_count);
+  ASSERT_EQ(true, last_callback_success_);
+
+  DisableTracing();
+}
+
+// Checks that a NACK callback is invoked if RequestGlobalDump() is called when
+// tracing is not enabled.
+TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  RegisterDumpProvider(&mdp1);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
+
+  last_callback_success_ = true;
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  EXPECT_FALSE(last_callback_success_);
+}
+
+// Checks that is the MemoryDumpManager is initialized after tracing already
+// began, it will still late-join the party (real use case: startup tracing).
+TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
+  MockMemoryDumpProvider mdp;
+  RegisterDumpProvider(&mdp);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  // First check that a RequestGlobalDump() issued before the MemoryDumpManager
+  // initialization gets NACK-ed cleanly.
+  {
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    EXPECT_FALSE(last_callback_success_);
+  }
+
+  // Now late-initialize the MemoryDumpManager and check that the
+  // RequestGlobalDump completes successfully.
+  {
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    InitializeMemoryDumpManager(false /* is_coordinator */);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    EXPECT_TRUE(last_callback_success_);
+  }
+  DisableTracing();
+}
+
+// This test (and the MemoryDumpManagerTestCoordinator below) crystallizes the
+// expectations of the chrome://tracing UI and chrome telemetry w.r.t. periodic
+// dumps in memory-infra, handling gracefully the transition between the legacy
+// and the new-style (JSON-based) TraceConfig.
+TEST_F(MemoryDumpManagerTest, TraceConfigExpectations) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
+
+  // Don't trigger the default behavior of the mock delegate in this test,
+  // which would short-circuit the dump request to the actual
+  // CreateProcessDump().
+  // We don't want to create any dump in this test, only check whether the dumps
+  // are requested or not.
+  ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
+
+  // Enabling memory-infra in a non-coordinator process should not trigger any
+  // periodic dumps.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
+  // process with a fully defined trigger config should NOT enable any periodic
+  // dumps.
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(1, 5));
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+}
+
+TEST_F(MemoryDumpManagerTest, TraceConfigExpectationsWhenIsCoordinator) {
+  InitializeMemoryDumpManager(true /* is_coordinator */);
+  MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
+  ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
+
+  // Enabling memory-infra with the legacy TraceConfig (category filter) in
+  // a coordinator process should enable periodic dumps.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_TRUE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process without specifying any "memory_dump_config" section should enable
+  // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
+  // is: ticking memory-infra should dump periodically with the default config.
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_NoTriggers());
+  EXPECT_TRUE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process with an empty "memory_dump_config" should NOT enable periodic
+  // dumps. This is the way telemetry is supposed to use memory-infra with
+  // only explicitly triggered dumps.
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process with a fully defined trigger config should cause periodic dumps to
+  // be performed in the correct order.
+  RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+
+  const int kHeavyDumpRate = 5;
+  const int kLightDumpPeriodMs = 1;
+  const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs;
+  // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
+  testing::InSequence sequence;
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+      .Times(kHeavyDumpRate - 1);
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+      .Times(kHeavyDumpRate - 2);
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+      .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args,
+                                      const MemoryDumpCallback& callback) {
+        ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
+      }));
+
+  // Swallow all the final spurious calls until tracing gets disabled.
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(_, _)).Times(AnyNumber());
+
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(
+          kLightDumpPeriodMs, kHeavyDumpPeriodMs));
+  run_loop.Run();
+  DisableTracing();
+}
+
+// Tests against race conditions that might arise when disabling tracing in the
+// middle of a global memory dump.
+TEST_F(MemoryDumpManagerTest, DisableTracingWhileDumping) {
+  base::WaitableEvent tracing_disabled_event(false, false);
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+
+  // Register a bound dump provider.
+  scoped_ptr<Thread> mdp_thread(new Thread("test thread"));
+  mdp_thread->Start();
+  MockMemoryDumpProvider mdp_with_affinity;
+  RegisterDumpProvider(&mdp_with_affinity, mdp_thread->task_runner(),
+                       kDefaultOptions);
+
+  // Register also an unbound dump provider. Unbound dump providers are always
+  // invoked after bound ones.
+  MockMemoryDumpProvider unbound_mdp;
+  RegisterDumpProvider(&unbound_mdp);
+
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp_with_affinity, OnMemoryDump(_, _))
+      .Times(1)
+      .WillOnce(
+          Invoke([&tracing_disabled_event](const MemoryDumpArgs&,
+                                           ProcessMemoryDump* pmd) -> bool {
+            tracing_disabled_event.Wait();
+
+            // At this point tracing has been disabled and the
+            // MemoryDumpManager.dump_thread_ has been shut down.
+            return true;
+          }));
+
+  // |unbound_mdp| should never be invoked because the thread for unbound dump
+  // providers has been shutdown in the meanwhile.
+  EXPECT_CALL(unbound_mdp, OnMemoryDump(_, _)).Times(0);
+
+  last_callback_success_ = true;
+  RunLoop run_loop;
+  MemoryDumpCallback callback =
+      Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+           MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                          MemoryDumpLevelOfDetail::DETAILED, callback);
+  DisableTracing();
+  tracing_disabled_event.Signal();
+  run_loop.Run();
+
+  // RequestGlobalMemoryDump() should be NACK-ed because one of the threads
+  // threads died before we had a chance to PostTask onto them.
+  EXPECT_FALSE(last_callback_success_);
+}
+
+TEST_F(MemoryDumpManagerTest, DumpOnBehalfOfOtherProcess) {
+  using trace_analyzer::Query;
+
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+
+  // Standard provider with default options (create dump for current process).
+  MemoryDumpProvider::Options options;
+  MockMemoryDumpProvider mdp1;
+  RegisterDumpProvider(&mdp1, nullptr, options);
+
+  // Provider with out-of-process dumping.
+  MockMemoryDumpProvider mdp2;
+  options.target_pid = 123;
+  RegisterDumpProvider(&mdp2, nullptr, options);
+
+  // Another provider with out-of-process dumping.
+  MockMemoryDumpProvider mdp3;
+  options.target_pid = 456;
+  RegisterDumpProvider(&mdp3, nullptr, options);
+
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp3, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
+
+  // Flush the trace into JSON.
+  trace_event::TraceResultBuffer buffer;
+  TraceResultBuffer::SimpleOutput trace_output;
+  buffer.SetOutputCallback(trace_output.GetCallback());
+  RunLoop run_loop;
+  buffer.Start();
+  trace_event::TraceLog::GetInstance()->Flush(
+      Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
+  run_loop.Run();
+  buffer.Finish();
+
+  // Analyze the JSON.
+  scoped_ptr<trace_analyzer::TraceAnalyzer> analyzer = make_scoped_ptr(
+      trace_analyzer::TraceAnalyzer::Create(trace_output.json_output));
+  trace_analyzer::TraceEventVector events;
+  analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
+                       &events);
+
+  ASSERT_EQ(3u, events.size());
+  ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123)));
+  ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456)));
+  ASSERT_EQ(1u, trace_analyzer::CountMatches(
+                    events, Query::EventPidIs(GetCurrentProcId())));
+  ASSERT_EQ(events[0]->id, events[1]->id);
+  ASSERT_EQ(events[0]->id, events[2]->id);
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
index 6e6551c..48eaaae 100644
--- a/base/trace_event/memory_dump_provider.h
+++ b/base/trace_event/memory_dump_provider.h
@@ -7,21 +7,48 @@
 
 #include "base/base_export.h"
 #include "base/macros.h"
+#include "base/process/process_handle.h"
+#include "base/trace_event/memory_dump_request_args.h"
 
 namespace base {
 namespace trace_event {
 
 class ProcessMemoryDump;
 
+// Args passed to OnMemoryDump(). This is to avoid rewriting all the subclasses
+// in the codebase when extending the MemoryDumpProvider API.
+struct MemoryDumpArgs {
+  MemoryDumpLevelOfDetail level_of_detail;
+};
+
 // The contract interface that memory dump providers must implement.
 class BASE_EXPORT MemoryDumpProvider {
  public:
+  // Optional arguments for MemoryDumpManager::RegisterDumpProvider().
+  struct Options {
+    Options() : target_pid(kNullProcessId) {}
+    explicit Options(ProcessId target_pid) : target_pid(target_pid) {}
+
+    // If the dump provider generates dumps on behalf of another process,
+    // |target_process| contains the pid of that process.
+    // The default value is kNullProcessId, which means that the dump provider
+    // generates dumps for the current process.
+    ProcessId target_pid;
+  };
+
   // 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.
+  // The |args| specify if the embedder should generate light/heavy dumps on
+  // dump requests. The embedder should return true if the |pmd| was
+  // successfully populated, false if something went wrong and the dump should
+  // be considered invalid.
   // (Note, the MemoryDumpManager has a fail-safe logic which will disable the
   // MemoryDumpProvider for the entire trace session if it fails consistently).
-  virtual bool OnMemoryDump(ProcessMemoryDump* pmd) = 0;
+  virtual bool OnMemoryDump(const MemoryDumpArgs& args,
+                            ProcessMemoryDump* pmd) = 0;
+
+  // Called by the MemoryDumpManager when an allocator should start or stop
+  // collecting extensive allocation data, if supported.
+  virtual void OnHeapProfilingEnabled(bool enabled) {}
 
  protected:
   MemoryDumpProvider() {}
diff --git a/base/trace_event/memory_dump_request_args.cc b/base/trace_event/memory_dump_request_args.cc
new file mode 100644
index 0000000..48b5ba6
--- /dev/null
+++ b/base/trace_event/memory_dump_request_args.cc
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_request_args.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
+  switch (dump_type) {
+    case MemoryDumpType::TASK_BEGIN:
+      return "task_begin";
+    case MemoryDumpType::TASK_END:
+      return "task_end";
+    case MemoryDumpType::PERIODIC_INTERVAL:
+      return "periodic_interval";
+    case MemoryDumpType::EXPLICITLY_TRIGGERED:
+      return "explicitly_triggered";
+  }
+  NOTREACHED();
+  return "unknown";
+}
+
+const char* MemoryDumpLevelOfDetailToString(
+    const MemoryDumpLevelOfDetail& level_of_detail) {
+  switch (level_of_detail) {
+    case MemoryDumpLevelOfDetail::LIGHT:
+      return "light";
+    case MemoryDumpLevelOfDetail::DETAILED:
+      return "detailed";
+  }
+  NOTREACHED();
+  return "unknown";
+}
+
+MemoryDumpLevelOfDetail StringToMemoryDumpLevelOfDetail(
+    const std::string& str) {
+  if (str == "light")
+    return MemoryDumpLevelOfDetail::LIGHT;
+  if (str == "detailed")
+    return MemoryDumpLevelOfDetail::DETAILED;
+  NOTREACHED();
+  return MemoryDumpLevelOfDetail::LAST;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_request_args.h b/base/trace_event/memory_dump_request_args.h
index 4d3763a..00d560e 100644
--- a/base/trace_event/memory_dump_request_args.h
+++ b/base/trace_event/memory_dump_request_args.h
@@ -8,6 +8,9 @@
 // This file defines the types and structs used to issue memory dump requests.
 // These are also used in the IPCs for coordinating inter-process memory dumps.
 
+#include <stdint.h>
+#include <string>
+
 #include "base/base_export.h"
 #include "base/callback.h"
 
@@ -24,17 +27,38 @@
   LAST = EXPLICITLY_TRIGGERED // For IPC macros.
 };
 
-using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
+// Tells the MemoryDumpProvider(s) how much detailed their dumps should be.
+// MemoryDumpProvider instances must guarantee that level of detail does not
+// affect the total size reported in the root node, but only the granularity of
+// the child MemoryAllocatorDump(s).
+enum class MemoryDumpLevelOfDetail {
+  LIGHT,           // Few entries, typically a fixed number, per dump.
+  DETAILED,        // Unrestricted amount of entries per dump.
+  LAST = DETAILED  // For IPC Macros.
+};
 
+// Initial request arguments for a global memory dump. (see
+// MemoryDumpManager::RequestGlobalMemoryDump()).
 struct BASE_EXPORT MemoryDumpRequestArgs {
   // Globally unique identifier. In multi-process dumps, all processes issue a
   // local dump with the same guid. This allows the trace importers to
   // reconstruct the global dump.
-  uint64 dump_guid;
+  uint64_t dump_guid;
 
   MemoryDumpType dump_type;
+  MemoryDumpLevelOfDetail level_of_detail;
 };
 
+using MemoryDumpCallback = Callback<void(uint64_t dump_guid, bool success)>;
+
+BASE_EXPORT const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type);
+
+BASE_EXPORT const char* MemoryDumpLevelOfDetailToString(
+    const MemoryDumpLevelOfDetail& level_of_detail);
+
+BASE_EXPORT MemoryDumpLevelOfDetail
+StringToMemoryDumpLevelOfDetail(const std::string& str);
+
 }  // namespace trace_event
 }  // namespace base
 
diff --git a/base/trace_event/memory_dump_session_state.cc b/base/trace_event/memory_dump_session_state.cc
index 433ac14..5aa79b1 100644
--- a/base/trace_event/memory_dump_session_state.cc
+++ b/base/trace_event/memory_dump_session_state.cc
@@ -7,8 +7,11 @@
 namespace base {
 namespace trace_event {
 
-MemoryDumpSessionState::MemoryDumpSessionState() {
-}
+MemoryDumpSessionState::MemoryDumpSessionState(
+    const scoped_refptr<StackFrameDeduplicator>& stack_frame_deduplicator,
+    const scoped_refptr<TypeNameDeduplicator>& type_name_deduplicator)
+    : stack_frame_deduplicator_(stack_frame_deduplicator),
+      type_name_deduplicator_(type_name_deduplicator) {}
 
 MemoryDumpSessionState::~MemoryDumpSessionState() {
 }
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
index cf29b85..6834471 100644
--- a/base/trace_event/memory_dump_session_state.h
+++ b/base/trace_event/memory_dump_session_state.h
@@ -5,10 +5,10 @@
 #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"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
 
 namespace base {
 namespace trace_event {
@@ -18,11 +18,33 @@
 class BASE_EXPORT MemoryDumpSessionState
     : public RefCountedThreadSafe<MemoryDumpSessionState> {
  public:
-  MemoryDumpSessionState();
+  MemoryDumpSessionState(
+      const scoped_refptr<StackFrameDeduplicator>& stack_frame_deduplicator,
+      const scoped_refptr<TypeNameDeduplicator>& type_name_deduplicator);
+
+  // Returns the stack frame deduplicator that should be used by memory dump
+  // providers when doing a heap dump.
+  StackFrameDeduplicator* stack_frame_deduplicator() {
+    return stack_frame_deduplicator_.get();
+  }
+
+  // Returns the type name deduplicator that should be used by memory dump
+  // providers when doing a heap dump.
+  TypeNameDeduplicator* type_name_deduplicator() {
+    return type_name_deduplicator_.get();
+  }
 
  private:
   friend class RefCountedThreadSafe<MemoryDumpSessionState>;
   ~MemoryDumpSessionState();
+
+  // Deduplicates backtraces in heap dumps so they can be written once when the
+  // trace is finalized.
+  scoped_refptr<StackFrameDeduplicator> stack_frame_deduplicator_;
+
+  // Deduplicates type names in heap dumps so they can be written once when the
+  // trace is finalized.
+  scoped_refptr<TypeNameDeduplicator> type_name_deduplicator_;
 };
 
 }  // namespace trace_event
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 54fcad6..1510672 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -4,12 +4,89 @@
 
 #include "base/trace_event/process_memory_dump.h"
 
+#include <errno.h>
+#include <vector>
+
+#include "base/process/process_metrics.h"
 #include "base/trace_event/process_memory_totals.h"
 #include "base/trace_event/trace_event_argument.h"
 
+#if defined(OS_POSIX)
+#include <sys/mman.h>
+#endif
+
 namespace base {
 namespace trace_event {
 
+namespace {
+
+const char kEdgeTypeOwnership[] = "ownership";
+
+std::string GetSharedGlobalAllocatorDumpName(
+    const MemoryAllocatorDumpGuid& guid) {
+  return "global/" + guid.ToString();
+}
+
+}  // namespace
+
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+// static
+size_t ProcessMemoryDump::CountResidentBytes(void* start_address,
+                                             size_t mapped_size) {
+  const size_t page_size = GetPageSize();
+  const uintptr_t start_pointer = reinterpret_cast<uintptr_t>(start_address);
+  DCHECK_EQ(0u, start_pointer % page_size);
+
+  // This function allocates a char vector of size number of pages in the given
+  // mapped_size. To avoid allocating a large array, the memory is split into
+  // chunks. Maximum size of vector allocated, will be
+  // kPageChunkSize / page_size.
+  const size_t kMaxChunkSize = 32 * 1024 * 1024;
+  size_t offset = 0;
+  size_t total_resident_size = 0;
+  int result = 0;
+  while (offset < mapped_size) {
+    void* chunk_start = reinterpret_cast<void*>(start_pointer + offset);
+    const size_t chunk_size = std::min(mapped_size - offset, kMaxChunkSize);
+    const size_t page_count = (chunk_size + page_size - 1) / page_size;
+    size_t resident_page_count = 0;
+
+#if defined(OS_MACOSX) || defined(OS_IOS)
+    std::vector<char> vec(page_count + 1);
+    // mincore in MAC does not fail with EAGAIN.
+    result = mincore(chunk_start, chunk_size, vec.data());
+    if (result)
+      break;
+
+    for (size_t i = 0; i < page_count; i++)
+      resident_page_count += vec[i] & MINCORE_INCORE ? 1 : 0;
+#else   // defined(OS_MACOSX) || defined(OS_IOS)
+    std::vector<unsigned char> vec(page_count + 1);
+    int error_counter = 0;
+    // HANDLE_EINTR tries for 100 times. So following the same pattern.
+    do {
+      result = mincore(chunk_start, chunk_size, vec.data());
+    } while (result == -1 && errno == EAGAIN && error_counter++ < 100);
+    if (result)
+      break;
+
+    for (size_t i = 0; i < page_count; i++)
+      resident_page_count += vec[i];
+#endif  // defined(OS_MACOSX) || defined(OS_IOS)
+
+    total_resident_size += resident_page_count * page_size;
+    offset += kMaxChunkSize;
+  }
+
+  DCHECK_EQ(0, result);
+  if (result) {
+    total_resident_size = 0;
+    LOG(ERROR) << "mincore() call failed. The resident size is invalid";
+  }
+  return total_resident_size;
+}
+#endif  // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+
 ProcessMemoryDump::ProcessMemoryDump(
     const scoped_refptr<MemoryDumpSessionState>& session_state)
     : has_process_totals_(false),
@@ -23,36 +100,155 @@
 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;
+  AddAllocatorDumpInternal(mad);  // Takes ownership of |mad|.
   return mad;
 }
 
+MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
+    const std::string& absolute_name,
+    const MemoryAllocatorDumpGuid& guid) {
+  MemoryAllocatorDump* mad = new MemoryAllocatorDump(absolute_name, this, guid);
+  AddAllocatorDumpInternal(mad);  // Takes ownership of |mad|.
+  return mad;
+}
+
+void ProcessMemoryDump::AddAllocatorDumpInternal(MemoryAllocatorDump* mad) {
+  DCHECK_EQ(0ul, allocator_dumps_.count(mad->absolute_name()));
+  allocator_dumps_storage_.push_back(mad);
+  allocator_dumps_[mad->absolute_name()] = mad;
+}
+
 MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
     const std::string& absolute_name) const {
   auto it = allocator_dumps_.find(absolute_name);
   return it == allocator_dumps_.end() ? nullptr : it->second;
 }
 
+MemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump(
+    const std::string& absolute_name) {
+  MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name);
+  return mad ? mad : CreateAllocatorDump(absolute_name);
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump(
+    const MemoryAllocatorDumpGuid& guid) {
+  // A shared allocator dump can be shared within a process and the guid could
+  // have been created already.
+  MemoryAllocatorDump* allocator_dump = GetSharedGlobalAllocatorDump(guid);
+  return allocator_dump ? allocator_dump
+                        : CreateAllocatorDump(
+                              GetSharedGlobalAllocatorDumpName(guid), guid);
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump(
+    const MemoryAllocatorDumpGuid& guid) const {
+  return GetAllocatorDump(GetSharedGlobalAllocatorDumpName(guid));
+}
+
+void ProcessMemoryDump::AddHeapDump(const std::string& absolute_name,
+                                    scoped_refptr<TracedValue> heap_dump) {
+  DCHECK_EQ(0ul, heap_dumps_.count(absolute_name));
+  heap_dumps_[absolute_name] = heap_dump;
+}
+
+void ProcessMemoryDump::Clear() {
+  if (has_process_totals_) {
+    process_totals_.Clear();
+    has_process_totals_ = false;
+  }
+
+  if (has_process_mmaps_) {
+    process_mmaps_.Clear();
+    has_process_mmaps_ = false;
+  }
+
+  allocator_dumps_storage_.clear();
+  allocator_dumps_.clear();
+  allocator_dumps_edges_.clear();
+  heap_dumps_.clear();
+}
+
+void ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) {
+  DCHECK(!other->has_process_totals() && !other->has_process_mmaps());
+
+  // Moves the ownership of all MemoryAllocatorDump(s) contained in |other|
+  // into this ProcessMemoryDump.
+  for (MemoryAllocatorDump* mad : other->allocator_dumps_storage_) {
+    // Check that we don't merge duplicates.
+    DCHECK_EQ(0ul, allocator_dumps_.count(mad->absolute_name()));
+    allocator_dumps_storage_.push_back(mad);
+    allocator_dumps_[mad->absolute_name()] = mad;
+  }
+  other->allocator_dumps_storage_.weak_clear();
+  other->allocator_dumps_.clear();
+
+  // Move all the edges.
+  allocator_dumps_edges_.insert(allocator_dumps_edges_.end(),
+                                other->allocator_dumps_edges_.begin(),
+                                other->allocator_dumps_edges_.end());
+  other->allocator_dumps_edges_.clear();
+
+  heap_dumps_.insert(other->heap_dumps_.begin(), other->heap_dumps_.end());
+  other->heap_dumps_.clear();
+}
+
 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();
   }
+
+  if (heap_dumps_.size() > 0) {
+    value->BeginDictionary("heaps");
+    for (const auto& name_and_dump : heap_dumps_)
+      value->SetValueWithCopiedName(name_and_dump.first, *name_and_dump.second);
+    value->EndDictionary();  // "heaps"
+  }
+
+  value->BeginArray("allocators_graph");
+  for (const MemoryAllocatorDumpEdge& edge : allocator_dumps_edges_) {
+    value->BeginDictionary();
+    value->SetString("source", edge.source.ToString());
+    value->SetString("target", edge.target.ToString());
+    value->SetInteger("importance", edge.importance);
+    value->SetString("type", edge.type);
+    value->EndDictionary();
+  }
+  value->EndArray();
+}
+
+void ProcessMemoryDump::AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
+                                         const MemoryAllocatorDumpGuid& target,
+                                         int importance) {
+  allocator_dumps_edges_.push_back(
+      {source, target, importance, kEdgeTypeOwnership});
+}
+
+void ProcessMemoryDump::AddOwnershipEdge(
+    const MemoryAllocatorDumpGuid& source,
+    const MemoryAllocatorDumpGuid& target) {
+  AddOwnershipEdge(source, target, 0 /* importance */);
+}
+
+void ProcessMemoryDump::AddSuballocation(const MemoryAllocatorDumpGuid& source,
+                                         const std::string& target_node_name) {
+  std::string child_mad_name = target_node_name + "/__" + source.ToString();
+  MemoryAllocatorDump* target_child_mad = CreateAllocatorDump(child_mad_name);
+  AddOwnershipEdge(source, target_child_mad->guid());
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index 889356d..a997c69 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -5,39 +5,147 @@
 #ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
 #define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
 
+#include <vector>
+
 #include "base/base_export.h"
 #include "base/containers/hash_tables.h"
 #include "base/containers/small_map.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
 #include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
 #include "base/trace_event/memory_dump_session_state.h"
 #include "base/trace_event/process_memory_maps.h"
 #include "base/trace_event/process_memory_totals.h"
 
+// Define COUNT_RESIDENT_BYTES_SUPPORTED if platform supports counting of the
+// resident memory.
+// TODO(crbug.com/542671): COUNT_RESIDENT_BYTES_SUPPORTED is disabled on iOS
+// as it cause memory corruption on iOS 9.0+ devices.
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_IOS)
+#define COUNT_RESIDENT_BYTES_SUPPORTED
+#endif
+
 namespace base {
 namespace trace_event {
 
 class ConvertableToTraceFormat;
 class MemoryDumpManager;
 class MemoryDumpSessionState;
+class TracedValue;
 
-// 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.
+// ProcessMemoryDump is as a strongly typed container which holds the dumps
+// produced by the MemoryDumpProvider(s) for a specific process.
 class BASE_EXPORT ProcessMemoryDump {
  public:
+  struct MemoryAllocatorDumpEdge {
+    MemoryAllocatorDumpGuid source;
+    MemoryAllocatorDumpGuid target;
+    int importance;
+    const char* type;
+  };
+
   // Maps allocator dumps absolute names (allocator_name/heap/subheap) to
   // MemoryAllocatorDump instances.
   using AllocatorDumpsMap =
       SmallMap<hash_map<std::string, MemoryAllocatorDump*>>;
 
+  using HeapDumpsMap =
+      SmallMap<hash_map<std::string, scoped_refptr<TracedValue>>>;
+
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+  // Returns the total bytes resident for a virtual address range, with given
+  // |start_address| and |mapped_size|. |mapped_size| is specified in bytes. The
+  // value returned is valid only if the given range is currently mmapped by the
+  // process. The |start_address| must be page-aligned.
+  static size_t CountResidentBytes(void* start_address, size_t mapped_size);
+#endif
+
   ProcessMemoryDump(const scoped_refptr<MemoryDumpSessionState>& session_state);
   ~ProcessMemoryDump();
 
+  // Creates a new MemoryAllocatorDump with the given name and returns the
+  // empty object back to the caller.
+  // Arguments:
+  //   absolute_name: a name that uniquely identifies allocator dumps produced
+  //       by this provider. It is possible to specify nesting by using a
+  //       path-like string (e.g., v8/isolate1/heap1, v8/isolate1/heap2).
+  //       Leading or trailing slashes are not allowed.
+  //   guid: an optional identifier, unique among all processes within the
+  //       scope of a global dump. This is only relevant when using
+  //       AddOwnershipEdge() to express memory sharing. If omitted,
+  //       it will be automatically generated.
+  // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
+  MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
+  MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name,
+                                           const MemoryAllocatorDumpGuid& guid);
+
+  // Looks up a MemoryAllocatorDump given its allocator and heap names, or
+  // nullptr if not found.
+  MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
+
+  MemoryAllocatorDump* GetOrCreateAllocatorDump(
+      const std::string& absolute_name);
+
+  // Creates a shared MemoryAllocatorDump, to express cross-process sharing.
+  // Shared allocator dumps are allowed to have duplicate guids within the
+  // global scope, in order to reference the same dump from multiple processes.
+  // See the design doc goo.gl/keU6Bf for reference usage patterns.
+  MemoryAllocatorDump* CreateSharedGlobalAllocatorDump(
+      const MemoryAllocatorDumpGuid& guid);
+
+  // Looks up a shared MemoryAllocatorDump given its guid.
+  MemoryAllocatorDump* GetSharedGlobalAllocatorDump(
+      const MemoryAllocatorDumpGuid& guid) const;
+
+  // Returns the map of the MemoryAllocatorDumps added to this dump.
+  const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
+
+  // Adds a heap dump for the allocator with |absolute_name|. The |TracedValue|
+  // must have the correct format. |trace_event::HeapDumper| will generate such
+  // a value from a |trace_event::AllocationRegister|.
+  void AddHeapDump(const std::string& absolute_name,
+                   scoped_refptr<TracedValue> heap_dump);
+
+  // Adds an ownership relationship between two MemoryAllocatorDump(s) with the
+  // semantics: |source| owns |target|, and has the effect of attributing
+  // the memory usage of |target| to |source|. |importance| is optional and
+  // relevant only for the cases of co-ownership, where it acts as a z-index:
+  // the owner with the highest importance will be attributed |target|'s memory.
+  void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
+                        const MemoryAllocatorDumpGuid& target,
+                        int importance);
+  void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
+                        const MemoryAllocatorDumpGuid& target);
+
+  const std::vector<MemoryAllocatorDumpEdge>& allocator_dumps_edges() const {
+    return allocator_dumps_edges_;
+  }
+
+  // Utility method to add a suballocation relationship with the following
+  // semantics: |source| is suballocated from |target_node_name|.
+  // This creates a child node of |target_node_name| and adds an ownership edge
+  // between |source| and the new child node. As a result, the UI will not
+  // account the memory of |source| in the target node.
+  void AddSuballocation(const MemoryAllocatorDumpGuid& source,
+                        const std::string& target_node_name);
+
+  const scoped_refptr<MemoryDumpSessionState>& session_state() const {
+    return session_state_;
+  }
+
+  // Removes all the MemoryAllocatorDump(s) contained in this instance. This
+  // ProcessMemoryDump can be safely reused as if it was new once this returns.
+  void Clear();
+
+  // Merges all MemoryAllocatorDump(s) contained in |other| inside this
+  // ProcessMemoryDump, transferring their ownership to this instance.
+  // |other| will be an empty ProcessMemoryDump after this method returns.
+  // This is to allow dump providers to pre-populate ProcessMemoryDump instances
+  // and later move their contents into the ProcessMemoryDump passed as argument
+  // of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
+  void TakeAllDumpsFrom(ProcessMemoryDump* other);
+
   // Called at trace generation time to populate the TracedValue.
   void AsValueInto(TracedValue* value) const;
 
@@ -49,28 +157,9 @@
   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:
+  void AddAllocatorDumpInternal(MemoryAllocatorDump* mad);
+
   ProcessMemoryTotals process_totals_;
   bool has_process_totals_;
 
@@ -78,6 +167,7 @@
   bool has_process_mmaps_;
 
   AllocatorDumpsMap allocator_dumps_;
+  HeapDumpsMap heap_dumps_;
 
   // ProcessMemoryDump handles the memory ownership of all its belongings.
   ScopedVector<MemoryAllocatorDump> allocator_dumps_storage_;
@@ -85,6 +175,9 @@
   // State shared among all PMDs instances created in a given trace session.
   scoped_refptr<MemoryDumpSessionState> session_state_;
 
+  // Keeps track of relationships between MemoryAllocatorDump(s).
+  std::vector<MemoryAllocatorDumpEdge> allocator_dumps_edges_;
+
   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
 };
 
diff --git a/base/trace_event/process_memory_dump_unittest.cc b/base/trace_event/process_memory_dump_unittest.cc
new file mode 100644
index 0000000..132bb47
--- /dev/null
+++ b/base/trace_event/process_memory_dump_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_dump.h"
+
+#include "base/memory/aligned_memory.h"
+#include "base/process/process_metrics.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(ProcessMemoryDumpTest, Clear) {
+  scoped_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr));
+  pmd1->CreateAllocatorDump("mad1");
+  pmd1->CreateAllocatorDump("mad2");
+  ASSERT_FALSE(pmd1->allocator_dumps().empty());
+
+  pmd1->process_totals()->set_resident_set_bytes(42);
+  pmd1->set_has_process_totals();
+
+  pmd1->process_mmaps()->AddVMRegion(ProcessMemoryMaps::VMRegion());
+  pmd1->set_has_process_mmaps();
+
+  pmd1->AddOwnershipEdge(MemoryAllocatorDumpGuid(42),
+                         MemoryAllocatorDumpGuid(4242));
+
+  MemoryAllocatorDumpGuid shared_mad_guid(1);
+  pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid);
+
+  pmd1->Clear();
+  ASSERT_TRUE(pmd1->allocator_dumps().empty());
+  ASSERT_TRUE(pmd1->allocator_dumps_edges().empty());
+  ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad1"));
+  ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2"));
+  ASSERT_FALSE(pmd1->has_process_totals());
+  ASSERT_FALSE(pmd1->has_process_mmaps());
+  ASSERT_TRUE(pmd1->process_mmaps()->vm_regions().empty());
+  ASSERT_EQ(nullptr, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid));
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  scoped_refptr<TracedValue> traced_value(new TracedValue());
+  pmd1->AsValueInto(traced_value.get());
+
+  // Check that the pmd can be reused and behaves as expected.
+  auto mad1 = pmd1->CreateAllocatorDump("mad1");
+  auto mad3 = pmd1->CreateAllocatorDump("mad3");
+  auto shared_mad = pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid);
+  ASSERT_EQ(3u, pmd1->allocator_dumps().size());
+  ASSERT_EQ(mad1, pmd1->GetAllocatorDump("mad1"));
+  ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2"));
+  ASSERT_EQ(mad3, pmd1->GetAllocatorDump("mad3"));
+  ASSERT_EQ(shared_mad, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid));
+
+  traced_value = new TracedValue();
+  pmd1->AsValueInto(traced_value.get());
+
+  pmd1.reset();
+}
+
+TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) {
+  scoped_refptr<TracedValue> traced_value(new TracedValue());
+
+  scoped_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr));
+  auto mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1");
+  auto mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2");
+  pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid());
+
+  scoped_ptr<ProcessMemoryDump> pmd2(new ProcessMemoryDump(nullptr));
+  auto mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1");
+  auto mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2");
+  pmd1->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid());
+
+  MemoryAllocatorDumpGuid shared_mad_guid(1);
+  auto shared_mad = pmd2->CreateSharedGlobalAllocatorDump(shared_mad_guid);
+
+  pmd1->TakeAllDumpsFrom(pmd2.get());
+
+  // Make sure that pmd2 is empty but still usable after it has been emptied.
+  ASSERT_TRUE(pmd2->allocator_dumps().empty());
+  ASSERT_TRUE(pmd2->allocator_dumps_edges().empty());
+  pmd2->CreateAllocatorDump("pmd2/this_mad_stays_with_pmd2");
+  ASSERT_EQ(1u, pmd2->allocator_dumps().size());
+  ASSERT_EQ(1u, pmd2->allocator_dumps().count("pmd2/this_mad_stays_with_pmd2"));
+  pmd2->AddOwnershipEdge(MemoryAllocatorDumpGuid(42),
+                         MemoryAllocatorDumpGuid(4242));
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  pmd2->AsValueInto(traced_value.get());
+
+  // Free the |pmd2| to check that the memory ownership of the two MAD(s)
+  // has been transferred to |pmd1|.
+  pmd2.reset();
+
+  // Now check that |pmd1| has been effectively merged.
+  ASSERT_EQ(5u, pmd1->allocator_dumps().size());
+  ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad1"));
+  ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
+  ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd2/mad1"));
+  ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
+  ASSERT_EQ(2u, pmd1->allocator_dumps_edges().size());
+  ASSERT_EQ(shared_mad, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid));
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  traced_value = new TracedValue();
+  pmd1->AsValueInto(traced_value.get());
+
+  pmd1.reset();
+}
+
+TEST(ProcessMemoryDumpTest, Suballocations) {
+  scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
+  const std::string allocator_dump_name = "fakealloc/allocated_objects";
+  pmd->CreateAllocatorDump(allocator_dump_name);
+
+  // Create one allocation with an auto-assigned guid and mark it as a
+  // suballocation of "fakealloc/allocated_objects".
+  auto pic1_dump = pmd->CreateAllocatorDump("picturemanager/picture1");
+  pmd->AddSuballocation(pic1_dump->guid(), allocator_dump_name);
+
+  // Same here, but this time create an allocation with an explicit guid.
+  auto pic2_dump = pmd->CreateAllocatorDump("picturemanager/picture2",
+                                            MemoryAllocatorDumpGuid(0x42));
+  pmd->AddSuballocation(pic2_dump->guid(), allocator_dump_name);
+
+  // Now check that AddSuballocation() has created anonymous child dumps under
+  // "fakealloc/allocated_objects".
+  auto anon_node_1_it = pmd->allocator_dumps().find(
+      allocator_dump_name + "/__" + pic1_dump->guid().ToString());
+  ASSERT_NE(pmd->allocator_dumps().end(), anon_node_1_it);
+
+  auto anon_node_2_it =
+      pmd->allocator_dumps().find(allocator_dump_name + "/__42");
+  ASSERT_NE(pmd->allocator_dumps().end(), anon_node_2_it);
+
+  // Finally check that AddSuballocation() has created also the
+  // edges between the pictures and the anonymous allocator child dumps.
+  bool found_edge[2]{false, false};
+  for (const auto& e : pmd->allocator_dumps_edges()) {
+    found_edge[0] |= (e.source == pic1_dump->guid() &&
+                      e.target == anon_node_1_it->second->guid());
+    found_edge[1] |= (e.source == pic2_dump->guid() &&
+                      e.target == anon_node_2_it->second->guid());
+  }
+  ASSERT_TRUE(found_edge[0]);
+  ASSERT_TRUE(found_edge[1]);
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  scoped_refptr<TracedValue> traced_value(new TracedValue());
+  pmd->AsValueInto(traced_value.get());
+
+  pmd.reset();
+}
+
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+TEST(ProcessMemoryDumpTest, CountResidentBytes) {
+  const size_t page_size = base::GetPageSize();
+
+  // Allocate few page of dirty memory and check if it is resident.
+  const size_t size1 = 5 * page_size;
+  scoped_ptr<char, base::AlignedFreeDeleter> memory1(
+      static_cast<char*>(base::AlignedAlloc(size1, page_size)));
+  memset(memory1.get(), 0, size1);
+  size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1);
+  ASSERT_EQ(res1, size1);
+
+  // Allocate a large memory segment (>32Mib).
+  const size_t kVeryLargeMemorySize = 34 * 1024 * 1024;
+  scoped_ptr<char, base::AlignedFreeDeleter> memory2(
+      static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size)));
+  memset(memory2.get(), 0, kVeryLargeMemorySize);
+  size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(),
+                                                      kVeryLargeMemorySize);
+  ASSERT_EQ(res2, kVeryLargeMemorySize);
+}
+#endif  // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_maps.cc b/base/trace_event/process_memory_maps.cc
index d553ee8..bb400de 100644
--- a/base/trace_event/process_memory_maps.cc
+++ b/base/trace_event/process_memory_maps.cc
@@ -16,6 +16,18 @@
 const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
 const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
 
+ProcessMemoryMaps::VMRegion::VMRegion()
+    : start_address(0),
+      size_in_bytes(0),
+      protection_flags(0),
+      byte_stats_private_dirty_resident(0),
+      byte_stats_private_clean_resident(0),
+      byte_stats_shared_dirty_resident(0),
+      byte_stats_shared_clean_resident(0),
+      byte_stats_swapped(0),
+      byte_stats_proportional_resident(0) {
+}
+
 ProcessMemoryMaps::ProcessMemoryMaps() {
 }
 
@@ -38,10 +50,15 @@
     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->SetString(
+        "pd", StringPrintf(kHexFmt, region.byte_stats_private_dirty_resident));
+    value->SetString(
+        "pc", StringPrintf(kHexFmt, region.byte_stats_private_clean_resident));
+    value->SetString(
+        "sd", StringPrintf(kHexFmt, region.byte_stats_shared_dirty_resident));
+    value->SetString(
+        "sc", StringPrintf(kHexFmt, region.byte_stats_shared_clean_resident));
+    value->SetString("sw", StringPrintf(kHexFmt, region.byte_stats_swapped));
     value->EndDictionary();
 
     value->EndDictionary();
@@ -49,5 +66,9 @@
   value->EndArray();
 }
 
+void ProcessMemoryMaps::Clear() {
+  vm_regions_.clear();
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/process_memory_maps.h b/base/trace_event/process_memory_maps.h
index dc1892f..b06a850 100644
--- a/base/trace_event/process_memory_maps.h
+++ b/base/trace_event/process_memory_maps.h
@@ -19,19 +19,26 @@
 // Data model for process-wide memory stats.
 class BASE_EXPORT ProcessMemoryMaps {
  public:
-  struct VMRegion {
+  struct BASE_EXPORT VMRegion {
     static const uint32 kProtectionFlagsRead;
     static const uint32 kProtectionFlagsWrite;
     static const uint32 kProtectionFlagsExec;
 
+    VMRegion();
+
     uint64 start_address;
     uint64 size_in_bytes;
     uint32 protection_flags;
     std::string mapped_file;
 
-    // private_resident + shared_resident = resident set size.
-    uint64 byte_stats_private_resident;
-    uint64 byte_stats_shared_resident;
+    // private_dirty_resident + private_clean_resident + shared_dirty_resident +
+    // shared_clean_resident = resident set size.
+    uint64 byte_stats_private_dirty_resident;
+    uint64 byte_stats_private_clean_resident;
+    uint64 byte_stats_shared_dirty_resident;
+    uint64 byte_stats_shared_clean_resident;
+
+    uint64 byte_stats_swapped;
 
     // For multiprocess accounting.
     uint64 byte_stats_proportional_resident;
@@ -46,6 +53,9 @@
   // Called at trace generation time to populate the TracedValue.
   void AsValueInto(TracedValue* value) const;
 
+  // Clears up all the VMRegion(s) stored.
+  void Clear();
+
  private:
   std::vector<VMRegion> vm_regions_;
 
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
index 680fa29..19f8d89 100644
--- a/base/trace_event/process_memory_maps_dump_provider.cc
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -4,35 +4,36 @@
 
 #include "base/trace_event/process_memory_maps_dump_provider.h"
 
-#include <cctype>
-#include <fstream>
-
+#include "base/files/scoped_file.h"
+#include "base/format_macros.h"
 #include "base/logging.h"
-#include "base/process/process_metrics.h"
+#include "base/strings/string_util.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;
+FILE* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
 
 namespace {
 
 const uint32 kMaxLineSize = 4096;
 
-bool ParseSmapsHeader(std::istream* smaps,
+bool ParseSmapsHeader(const char* header_line,
                       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;
+  uint64 end_addr = 0;
+  char protection_flags[5] = {0};
+  char mapped_file[kMaxLineSize];
+
+  if (sscanf(header_line, "%" SCNx64 "-%" SCNx64 " %4c %*s %*s %*s%4095[^\n]\n",
+             &region->start_address, &end_addr, protection_flags,
+             mapped_file) != 4)
+    return false;
+
   if (end_addr > region->start_address) {
     region->size_in_bytes = end_addr - region->start_address;
   } else {
@@ -42,8 +43,6 @@
   }
 
   region->protection_flags = 0;
-  *smaps >> protection_flags;
-  CHECK_EQ(4UL, protection_flags.size());
   if (protection_flags[0] == 'r') {
     region->protection_flags |=
         ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
@@ -56,82 +55,70 @@
     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;
+  TrimWhitespaceASCII(region->mapped_file, TRIM_ALL, &region->mapped_file);
 
   return res;
 }
 
-uint64 ReadCounterBytes(std::istream* smaps) {
+uint64 ReadCounterBytes(char* counter_line) {
   uint64 counter_value = 0;
-  *smaps >> std::dec >> counter_value;
+  int res = sscanf(counter_line, "%*s %" SCNu64 " kB", &counter_value);
+  DCHECK_EQ(1, res);
   return counter_value * 1024;
 }
 
-uint32 ParseSmapsCounter(std::istream* smaps,
+uint32 ParseSmapsCounter(char* counter_line,
                          ProcessMemoryMaps::VMRegion* region) {
   // A smaps counter lines looks as follows: "RSS:  0 Kb\n"
-  uint32 res = 0;
-  std::string counter_name;
-  *smaps >> counter_name;
+  uint32 res = 1;
+  char counter_name[20];
+  int did_read = sscanf(counter_line, "%19[^\n ]", counter_name);
+  DCHECK_EQ(1, did_read);
 
-  // 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;
+  if (strcmp(counter_name, "Pss:") == 0) {
+    region->byte_stats_proportional_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Private_Dirty:") == 0) {
+    region->byte_stats_private_dirty_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Private_Clean:") == 0) {
+    region->byte_stats_private_clean_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Shared_Dirty:") == 0) {
+    region->byte_stats_shared_dirty_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Shared_Clean:") == 0) {
+    region->byte_stats_shared_clean_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Swap:") == 0) {
+    region->byte_stats_swapped = ReadCounterBytes(counter_line);
+  } else {
+    res = 0;
   }
 
-#ifndef NDEBUG
-  // Paranoid check against changes of the Kernel /proc interface.
-  if (res) {
-    std::string unit;
-    *smaps >> unit;
-    DCHECK_EQ("kB", unit);
-  }
-#endif
-
-  smaps->ignore(kMaxLineSize, '\n');
-
   return res;
 }
 
-uint32 ReadLinuxProcSmapsFile(std::istream* smaps, ProcessMemoryMaps* pmm) {
-  if (!smaps->good())
+uint32 ReadLinuxProcSmapsFile(FILE* smaps_file, ProcessMemoryMaps* pmm) {
+  if (!smaps_file)
     return 0;
 
-  const uint32 kNumExpectedCountersPerRegion = 5;
+  fseek(smaps_file, 0, SEEK_SET);
+
+  char line[kMaxLineSize];
+  const uint32 kNumExpectedCountersPerRegion = 6;
   uint32 counters_parsed_for_current_region = 0;
   uint32 num_valid_regions = 0;
   ProcessMemoryMaps::VMRegion region;
   bool should_add_current_region = false;
   for (;;) {
-    int next = smaps->peek();
-    if (next == std::ifstream::traits_type::eof() || next == '\n')
+    line[0] = '\0';
+    if (fgets(line, kMaxLineSize, smaps_file) == nullptr)
       break;
-    if (isxdigit(next) && !isupper(next)) {
-      region = {0};
+    DCHECK_GT(strlen(line), 0u);
+    if (isxdigit(line[0]) && !isupper(line[0])) {
+      region = ProcessMemoryMaps::VMRegion();
       counters_parsed_for_current_region = 0;
-      should_add_current_region = ParseSmapsHeader(smaps, &region);
+      should_add_current_region = ParseSmapsHeader(line, &region);
     } else {
-      counters_parsed_for_current_region += ParseSmapsCounter(smaps, &region);
+      counters_parsed_for_current_region += ParseSmapsCounter(line, &region);
       DCHECK_LE(counters_parsed_for_current_region,
                 kNumExpectedCountersPerRegion);
       if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
@@ -147,7 +134,6 @@
 }
 
 }  // namespace
-#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
 // static
 ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() {
@@ -161,27 +147,26 @@
 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;
+// Called at trace dump point time. Creates a snapshot of the memory maps for
+// the current process.
+bool ProcessMemoryMapsDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
+                                                 ProcessMemoryDump* pmd) {
+  // Snapshot of memory maps is not taken for light dump requests.
+  if (args.level_of_detail == MemoryDumpLevelOfDetail::LIGHT)
+    return true;
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+  uint32 res = 0;
   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());
+    ScopedFILE smaps_file(fopen("/proc/self/smaps", "r"));
+    res = ReadLinuxProcSmapsFile(smaps_file.get(), 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;
 }
 
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h
index c73c4d2..f302a48 100644
--- a/base/trace_event/process_memory_maps_dump_provider.h
+++ b/base/trace_event/process_memory_maps_dump_provider.h
@@ -5,8 +5,6 @@
 #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"
@@ -20,14 +18,15 @@
   static ProcessMemoryMapsDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    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;
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_NACL)
+  static FILE* proc_smaps_for_testing;
 #endif
 
   ProcessMemoryMapsDumpProvider();
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
index e45d30a..cce33eb 100644
--- a/base/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -4,9 +4,7 @@
 
 #include "base/trace_event/process_memory_maps_dump_provider.h"
 
-#include <fstream>
-#include <sstream>
-
+#include "base/files/file_util.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/process_memory_maps.h"
 #include "base/trace_event/trace_event_argument.h"
@@ -15,7 +13,6 @@
 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"
@@ -29,7 +26,7 @@
     "Referenced:          296 kB\n"
     "Anonymous:            68 kB\n"
     "AnonHugePages:         0 kB\n"
-    "Swap:                  0 kB\n"
+    "Swap:                  4 kB\n"
     "KernelPageSize:        4 kB\n"
     "MMUPageSize:           4 kB\n"
     "Locked:                0 kB\n"
@@ -104,35 +101,42 @@
     "MMUPageSize:           4 kB\n"
     "Locked:                0 kB\n"
     "VmFlags: rd wr mr mw me ac sd\n";
+
+void CreateAndSetSmapsFileForTesting(const char* smaps_string,
+                                     ScopedFILE& file) {
+  FilePath temp_path;
+  FILE* temp_file = CreateAndOpenTemporaryFile(&temp_path);
+  file.reset(temp_file);
+  ASSERT_TRUE(temp_file);
+
+  ASSERT_TRUE(base::WriteFileDescriptor(fileno(temp_file), smaps_string,
+                                        strlen(smaps_string)));
+}
+
 }  // namespace
 
 TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
   const uint32 kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
   const uint32 kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
   const uint32 kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+  const MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
 
   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);
+  ProcessMemoryDump pmd_invalid(nullptr /* session_state */);
+  ScopedFILE empty_file(OpenFile(FilePath("/dev/null"), "r"));
+  ASSERT_TRUE(empty_file.get());
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = empty_file.get();
+  pmmdp->OnMemoryDump(dump_args, &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);
+  ScopedFILE temp_file1;
+  CreateAndSetSmapsFileForTesting(kTestSmaps1, temp_file1);
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = temp_file1.get();
+  pmmdp->OnMemoryDump(dump_args, &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());
@@ -142,22 +146,29 @@
   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(228 * 1024UL, regions_1[0].byte_stats_shared_clean_resident);
+  EXPECT_EQ(0UL, regions_1[0].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(0UL, regions_1[0].byte_stats_private_clean_resident);
+  EXPECT_EQ(68 * 1024UL, regions_1[0].byte_stats_private_dirty_resident);
+  EXPECT_EQ(4 * 1024UL, regions_1[0].byte_stats_swapped);
 
   EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
   EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
   EXPECT_EQ(kProtW, regions_1[1].protection_flags);
   EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
   EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_proportional_resident);
-  EXPECT_EQ((120 + 4) * 1024UL, regions_1[1].byte_stats_shared_resident);
-  EXPECT_EQ((60 + 8) * 1024UL, regions_1[1].byte_stats_private_resident);
+  EXPECT_EQ(120 * 1024UL, regions_1[1].byte_stats_shared_clean_resident);
+  EXPECT_EQ(4 * 1024UL, regions_1[1].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(60 * 1024UL, regions_1[1].byte_stats_private_clean_resident);
+  EXPECT_EQ(8 * 1024UL, regions_1[1].byte_stats_private_dirty_resident);
+  EXPECT_EQ(0 * 1024UL, regions_1[1].byte_stats_swapped);
 
   // Parse the 2nd smaps file.
   ProcessMemoryDump pmd_2(nullptr /* session_state */);
-  std::istringstream test_smaps_2(kTestSmaps2);
-  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
-  pmmdp->OnMemoryDump(&pmd_2);
+  ScopedFILE temp_file2;
+  CreateAndSetSmapsFileForTesting(kTestSmaps2, temp_file2);
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = temp_file2.get();
+  pmmdp->OnMemoryDump(dump_args, &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());
@@ -166,10 +177,12 @@
   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);
+  EXPECT_EQ(16 * 1024UL, regions_2[0].byte_stats_shared_clean_resident);
+  EXPECT_EQ(12 * 1024UL, regions_2[0].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(8 * 1024UL, regions_2[0].byte_stats_private_clean_resident);
+  EXPECT_EQ(4 * 1024UL, regions_2[0].byte_stats_private_dirty_resident);
+  EXPECT_EQ(0 * 1024UL, regions_2[0].byte_stats_swapped);
 }
-#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/process_memory_totals.cc b/base/trace_event/process_memory_totals.cc
index 9b0c377..de27ab3 100644
--- a/base/trace_event/process_memory_totals.cc
+++ b/base/trace_event/process_memory_totals.cc
@@ -11,9 +11,36 @@
 namespace base {
 namespace trace_event {
 
+ProcessMemoryTotals::ProcessMemoryTotals()
+    : resident_set_bytes_(0),
+      peak_resident_set_bytes_(0),
+      is_peak_rss_resetable_(false) {
+}
+
+ProcessMemoryTotals::~ProcessMemoryTotals() {}
+
 void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
   value->SetString("resident_set_bytes",
                    StringPrintf("%" PRIx64, resident_set_bytes_));
+  if (peak_resident_set_bytes_ > 0) {
+    value->SetString("peak_resident_set_bytes",
+                     StringPrintf("%" PRIx64, peak_resident_set_bytes_));
+    value->SetBoolean("is_peak_rss_resetable", is_peak_rss_resetable_);
+  }
+
+  for (const auto it : extra_fields_) {
+    value->SetString(it.first, StringPrintf("%" PRIx64, it.second));
+  }
+}
+
+void ProcessMemoryTotals::Clear() {
+  resident_set_bytes_ = 0;
+}
+
+void ProcessMemoryTotals::SetExtraFieldInBytes(const char* name,
+                                               uint64_t value) {
+  DCHECK_EQ(0u, extra_fields_.count(name));
+  extra_fields_[name] = value;
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/process_memory_totals.h b/base/trace_event/process_memory_totals.h
index 29c94c9..eb7757c 100644
--- a/base/trace_event/process_memory_totals.h
+++ b/base/trace_event/process_memory_totals.h
@@ -5,6 +5,8 @@
 #ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
 #define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
 
+#include <map>
+
 #include "base/base_export.h"
 #include "base/basictypes.h"
 
@@ -16,16 +18,39 @@
 // Data model for process-wide memory stats.
 class BASE_EXPORT ProcessMemoryTotals {
  public:
-  ProcessMemoryTotals() : resident_set_bytes_(0) {}
+  ProcessMemoryTotals();
+  ~ProcessMemoryTotals();
 
   // 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; }
+  // Clears up all the data collected.
+  void Clear();
+
+  uint64_t resident_set_bytes() const { return resident_set_bytes_; }
+  void set_resident_set_bytes(uint64_t value) { resident_set_bytes_ = value; }
+
+  uint64_t peak_resident_set_bytes() const { return peak_resident_set_bytes_; }
+  void set_peak_resident_set_bytes(uint64_t value) {
+    peak_resident_set_bytes_ = value;
+  }
+
+  // On some platforms (recent linux kernels, see goo.gl/sMvAVz) the peak rss
+  // can be reset. When is_peak_rss_resettable == true, the peak refers to
+  // peak from the previous measurement. When false, it is the absolute peak
+  // since the start of the process.
+  bool is_peak_rss_resetable() const { return is_peak_rss_resetable_; }
+  void set_is_peak_rss_resetable(bool value) { is_peak_rss_resetable_ = value; }
+
+  void SetExtraFieldInBytes(const char* name, uint64_t value);
 
  private:
-  uint64 resident_set_bytes_;
+  uint64_t resident_set_bytes_;
+  uint64_t peak_resident_set_bytes_;
+  bool is_peak_rss_resetable_;
+
+  // Extra metrics for OS-specific statistics.
+  std::map<const char*, uint64_t> extra_fields_;
 
   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
 };
diff --git a/base/trace_event/process_memory_totals_dump_provider.cc b/base/trace_event/process_memory_totals_dump_provider.cc
index 06b537c..83015f8 100644
--- a/base/trace_event/process_memory_totals_dump_provider.cc
+++ b/base/trace_event/process_memory_totals_dump_provider.cc
@@ -8,23 +8,23 @@
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/process_memory_totals.h"
 
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include <fcntl.h>
+
+#include "base/files/file_util.h"
+
+namespace {
+bool kernel_supports_rss_peak_reset = true;
+const char kClearPeakRssCommand[] = "5";
+}
+#endif
+
 namespace base {
 namespace trace_event {
 
 // static
 uint64 ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
 
-namespace {
-
-ProcessMetrics* CreateProcessMetricsForCurrentProcess() {
-#if !defined(OS_MACOSX) || defined(OS_IOS)
-  return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle());
-#else
-  return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle(), NULL);
-#endif
-}
-}  // namespace
-
 // static
 ProcessMemoryTotalsDumpProvider*
 ProcessMemoryTotalsDumpProvider::GetInstance() {
@@ -34,21 +34,50 @@
 }
 
 ProcessMemoryTotalsDumpProvider::ProcessMemoryTotalsDumpProvider()
-    : process_metrics_(CreateProcessMetricsForCurrentProcess()) {
-}
+    : process_metrics_(ProcessMetrics::CreateCurrentProcessMetrics()) {}
 
 ProcessMemoryTotalsDumpProvider::~ProcessMemoryTotalsDumpProvider() {
 }
 
 // Called at trace dump point time. Creates a snapshot the memory counters for
 // the current process.
-bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
+                                                   ProcessMemoryDump* pmd) {
   const uint64 rss_bytes = rss_bytes_for_testing
                                ? rss_bytes_for_testing
                                : process_metrics_->GetWorkingSetSize();
 
+  uint64 peak_rss_bytes = 0;
+
+#if !defined(OS_IOS)
+  peak_rss_bytes = process_metrics_->GetPeakWorkingSetSize();
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  if (kernel_supports_rss_peak_reset) {
+    // TODO(ssid): Fix crbug.com/461788 to write to the file from sandboxed
+    // processes.
+    int clear_refs_fd = open("/proc/self/clear_refs", O_WRONLY);
+    if (clear_refs_fd > 0 &&
+        WriteFileDescriptor(clear_refs_fd, kClearPeakRssCommand,
+                            sizeof(kClearPeakRssCommand))) {
+      pmd->process_totals()->set_is_peak_rss_resetable(true);
+    } else {
+      kernel_supports_rss_peak_reset = false;
+    }
+    close(clear_refs_fd);
+  }
+#elif defined(OS_MACOSX)
+  size_t private_bytes;
+  bool res = process_metrics_->GetMemoryBytes(&private_bytes,
+                                              nullptr /* shared_bytes */);
+  if (res) {
+    pmd->process_totals()->SetExtraFieldInBytes("private_bytes", private_bytes);
+  }
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+#endif  // !defined(OS_IOS)
+
   if (rss_bytes > 0) {
     pmd->process_totals()->set_resident_set_bytes(rss_bytes);
+    pmd->process_totals()->set_peak_resident_set_bytes(peak_rss_bytes);
     pmd->set_has_process_totals();
     return true;
   }
diff --git a/base/trace_event/process_memory_totals_dump_provider.h b/base/trace_event/process_memory_totals_dump_provider.h
index 6c86eb6..66d4f99 100644
--- a/base/trace_event/process_memory_totals_dump_provider.h
+++ b/base/trace_event/process_memory_totals_dump_provider.h
@@ -22,7 +22,8 @@
   static ProcessMemoryTotalsDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override;
 
  private:
   friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>;
diff --git a/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
index f9bb6c0..4ec37f5 100644
--- a/base/trace_event/process_memory_totals_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -12,18 +12,19 @@
 namespace trace_event {
 
 TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
+  const MemoryDumpArgs high_detail_args = {MemoryDumpLevelOfDetail::DETAILED};
   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());
+  pmtdp->OnMemoryDump(high_detail_args, 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());
+  pmtdp->OnMemoryDump(high_detail_args, pmd_after.get());
 
   ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
 
diff --git a/base/trace_event/trace_buffer.cc b/base/trace_event/trace_buffer.cc
new file mode 100644
index 0000000..5d8a9bf
--- /dev/null
+++ b/base/trace_event/trace_buffer.cc
@@ -0,0 +1,399 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_buffer.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+class TraceBufferRingBuffer : public TraceBuffer {
+ public:
+  TraceBufferRingBuffer(size_t max_chunks)
+      : max_chunks_(max_chunks),
+        recyclable_chunks_queue_(new size_t[queue_capacity()]),
+        queue_head_(0),
+        queue_tail_(max_chunks),
+        current_iteration_index_(0),
+        current_chunk_seq_(1) {
+    chunks_.reserve(max_chunks);
+    for (size_t i = 0; i < max_chunks; ++i)
+      recyclable_chunks_queue_[i] = i;
+  }
+
+  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].release();
+    chunks_[*index] = NULL;  // Put NULL in the slot of a in-flight chunk.
+    if (chunk)
+      chunk->Reset(current_chunk_seq_++);
+    else
+      chunk = new TraceBufferChunk(current_chunk_seq_++);
+
+    return 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] = std::move(chunk);
+    recyclable_chunks_queue_[queue_tail_] = index;
+    queue_tail_ = NextQueueIndex(queue_tail_);
+  }
+
+  bool IsFull() const override { return false; }
+
+  size_t Size() const override {
+    // This is approximate because not all of the chunks are full.
+    return chunks_.size() * TraceBufferChunk::kTraceBufferChunkSize;
+  }
+
+  size_t Capacity() const override {
+    return max_chunks_ * TraceBufferChunk::kTraceBufferChunkSize;
+  }
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+    if (handle.chunk_index >= chunks_.size())
+      return NULL;
+    TraceBufferChunk* chunk = chunks_[handle.chunk_index].get();
+    if (!chunk || chunk->seq() != handle.chunk_seq)
+      return NULL;
+    return chunk->GetEventAt(handle.event_index);
+  }
+
+  const TraceBufferChunk* NextChunk() override {
+    if (chunks_.empty())
+      return NULL;
+
+    while (current_iteration_index_ != queue_tail_) {
+      size_t chunk_index = recyclable_chunks_queue_[current_iteration_index_];
+      current_iteration_index_ = NextQueueIndex(current_iteration_index_);
+      if (chunk_index >= chunks_.size())  // Skip uninitialized chunks.
+        continue;
+      DCHECK(chunks_[chunk_index]);
+      return chunks_[chunk_index].get();
+    }
+    return NULL;
+  }
+
+  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].get();
+      cloned_buffer->chunks_.push_back(chunk ? chunk->Clone() : NULL);
+    }
+    return std::move(cloned_buffer);
+  }
+
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    overhead->Add("TraceBufferRingBuffer", sizeof(*this));
+    for (size_t queue_index = queue_head_; queue_index != queue_tail_;
+         queue_index = NextQueueIndex(queue_index)) {
+      size_t chunk_index = recyclable_chunks_queue_[queue_index];
+      if (chunk_index >= chunks_.size())  // Skip uninitialized chunks.
+        continue;
+      chunks_[chunk_index]->EstimateTraceMemoryOverhead(overhead);
+    }
+  }
+
+ private:
+  class ClonedTraceBuffer : public TraceBuffer {
+   public:
+    ClonedTraceBuffer() : current_iteration_index_(0) {}
+
+    // The only implemented method.
+    const TraceBufferChunk* NextChunk() override {
+      return current_iteration_index_ < chunks_.size()
+                 ? chunks_[current_iteration_index_++].get()
+                 : NULL;
+    }
+
+    scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+      NOTIMPLEMENTED();
+      return scoped_ptr<TraceBufferChunk>();
+    }
+    void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk>) override {
+      NOTIMPLEMENTED();
+    }
+    bool IsFull() const override { return false; }
+    size_t Size() const override { return 0; }
+    size_t Capacity() const override { return 0; }
+    TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+      return NULL;
+    }
+    scoped_ptr<TraceBuffer> CloneForIteration() const override {
+      NOTIMPLEMENTED();
+      return scoped_ptr<TraceBuffer>();
+    }
+    void EstimateTraceMemoryOverhead(
+        TraceEventMemoryOverhead* overhead) override {
+      NOTIMPLEMENTED();
+    }
+
+    size_t current_iteration_index_;
+    std::vector<scoped_ptr<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_;
+  std::vector<scoped_ptr<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() * TraceBufferChunk::kTraceBufferChunkSize;
+  }
+
+  size_t Capacity() const override {
+    return max_chunks_ * TraceBufferChunk::kTraceBufferChunkSize;
+  }
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+    if (handle.chunk_index >= chunks_.size())
+      return NULL;
+    TraceBufferChunk* chunk = chunks_[handle.chunk_index];
+    if (!chunk || chunk->seq() != handle.chunk_seq)
+      return NULL;
+    return chunk->GetEventAt(handle.event_index);
+  }
+
+  const TraceBufferChunk* NextChunk() override {
+    while (current_iteration_index_ < chunks_.size()) {
+      // Skip in-flight chunks.
+      const TraceBufferChunk* chunk = chunks_[current_iteration_index_++];
+      if (chunk)
+        return chunk;
+    }
+    return NULL;
+  }
+
+  scoped_ptr<TraceBuffer> CloneForIteration() const override {
+    NOTIMPLEMENTED();
+    return scoped_ptr<TraceBuffer>();
+  }
+
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    const size_t chunks_ptr_vector_allocated_size =
+        sizeof(*this) + max_chunks_ * sizeof(decltype(chunks_)::value_type);
+    const size_t chunks_ptr_vector_resident_size =
+        sizeof(*this) + chunks_.size() * sizeof(decltype(chunks_)::value_type);
+    overhead->Add("TraceBufferVector", chunks_ptr_vector_allocated_size,
+                  chunks_ptr_vector_resident_size);
+    for (size_t i = 0; i < chunks_.size(); ++i) {
+      TraceBufferChunk* chunk = chunks_[i];
+      // Skip the in-flight (nullptr) chunks. They will be accounted by the
+      // per-thread-local dumpers, see ThreadLocalEventBuffer::OnMemoryDump.
+      if (chunk)
+        chunk->EstimateTraceMemoryOverhead(overhead);
+    }
+  }
+
+ private:
+  size_t in_flight_chunk_count_;
+  size_t current_iteration_index_;
+  size_t max_chunks_;
+  ScopedVector<TraceBufferChunk> chunks_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceBufferVector);
+};
+
+}  // namespace
+
+TraceBufferChunk::TraceBufferChunk(uint32 seq) : next_free_(0), seq_(seq) {}
+
+TraceBufferChunk::~TraceBufferChunk() {}
+
+void TraceBufferChunk::Reset(uint32 new_seq) {
+  for (size_t i = 0; i < next_free_; ++i)
+    chunk_[i].Reset();
+  next_free_ = 0;
+  seq_ = new_seq;
+  cached_overhead_estimate_.reset();
+}
+
+TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
+  DCHECK(!IsFull());
+  *event_index = next_free_++;
+  return &chunk_[*event_index];
+}
+
+scoped_ptr<TraceBufferChunk> TraceBufferChunk::Clone() const {
+  scoped_ptr<TraceBufferChunk> cloned_chunk(new TraceBufferChunk(seq_));
+  cloned_chunk->next_free_ = next_free_;
+  for (size_t i = 0; i < next_free_; ++i)
+    cloned_chunk->chunk_[i].CopyFrom(chunk_[i]);
+  return cloned_chunk;
+}
+
+void TraceBufferChunk::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  if (!cached_overhead_estimate_) {
+    cached_overhead_estimate_.reset(new TraceEventMemoryOverhead);
+
+    // When estimating the size of TraceBufferChunk, exclude the array of trace
+    // events, as they are computed individually below.
+    cached_overhead_estimate_->Add("TraceBufferChunk",
+                                   sizeof(*this) - sizeof(chunk_));
+  }
+
+  const size_t num_cached_estimated_events =
+      cached_overhead_estimate_->GetCount("TraceEvent");
+  DCHECK_LE(num_cached_estimated_events, size());
+
+  if (IsFull() && num_cached_estimated_events == size()) {
+    overhead->Update(*cached_overhead_estimate_);
+    return;
+  }
+
+  for (size_t i = num_cached_estimated_events; i < size(); ++i)
+    chunk_[i].EstimateTraceMemoryOverhead(cached_overhead_estimate_.get());
+
+  if (IsFull()) {
+    cached_overhead_estimate_->AddSelf();
+  } else {
+    // The unused TraceEvents in |chunks_| are not cached. They will keep
+    // changing as new TraceEvents are added to this chunk, so they are
+    // computed on the fly.
+    const size_t num_unused_trace_events = capacity() - size();
+    overhead->Add("TraceEvent (unused)",
+                  num_unused_trace_events * sizeof(TraceEvent));
+  }
+
+  overhead->Update(*cached_overhead_estimate_);
+}
+
+TraceResultBuffer::OutputCallback
+TraceResultBuffer::SimpleOutput::GetCallback() {
+  return Bind(&SimpleOutput::Append, Unretained(this));
+}
+
+void TraceResultBuffer::SimpleOutput::Append(
+    const std::string& json_trace_output) {
+  json_output += json_trace_output;
+}
+
+TraceResultBuffer::TraceResultBuffer() : append_comma_(false) {}
+
+TraceResultBuffer::~TraceResultBuffer() {}
+
+void TraceResultBuffer::SetOutputCallback(
+    const OutputCallback& json_chunk_callback) {
+  output_callback_ = json_chunk_callback;
+}
+
+void TraceResultBuffer::Start() {
+  append_comma_ = false;
+  output_callback_.Run("[");
+}
+
+void TraceResultBuffer::AddFragment(const std::string& trace_fragment) {
+  if (append_comma_)
+    output_callback_.Run(",");
+  append_comma_ = true;
+  output_callback_.Run(trace_fragment);
+}
+
+void TraceResultBuffer::Finish() {
+  output_callback_.Run("]");
+}
+
+TraceBuffer* TraceBuffer::CreateTraceBufferRingBuffer(size_t max_chunks) {
+  return new TraceBufferRingBuffer(max_chunks);
+}
+
+TraceBuffer* TraceBuffer::CreateTraceBufferVectorOfSize(size_t max_chunks) {
+  return new TraceBufferVector(max_chunks);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_buffer.h b/base/trace_event/trace_buffer.h
new file mode 100644
index 0000000..d54bd74
--- /dev/null
+++ b/base/trace_event/trace_buffer.h
@@ -0,0 +1,130 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_BUFFER_H_
+#define BASE_TRACE_EVENT_TRACE_BUFFER_H_
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+
+namespace trace_event {
+
+// TraceBufferChunk is the basic unit of TraceBuffer.
+class BASE_EXPORT TraceBufferChunk {
+ public:
+  explicit TraceBufferChunk(uint32 seq);
+  ~TraceBufferChunk();
+
+  void Reset(uint32 new_seq);
+  TraceEvent* AddTraceEvent(size_t* event_index);
+  bool IsFull() const { return next_free_ == kTraceBufferChunkSize; }
+
+  uint32 seq() const { return seq_; }
+  size_t capacity() const { return kTraceBufferChunkSize; }
+  size_t size() const { return next_free_; }
+
+  TraceEvent* GetEventAt(size_t index) {
+    DCHECK(index < size());
+    return &chunk_[index];
+  }
+  const TraceEvent* GetEventAt(size_t index) const {
+    DCHECK(index < size());
+    return &chunk_[index];
+  }
+
+  scoped_ptr<TraceBufferChunk> Clone() const;
+
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+  // These values must be kept consistent with the numbers of bits of
+  // chunk_index and event_index fields in TraceEventHandle
+  // (in trace_event_impl.h).
+  static const size_t kMaxChunkIndex = (1u << 26) - 1;
+  static const size_t kTraceBufferChunkSize = 64;
+
+ private:
+  size_t next_free_;
+  scoped_ptr<TraceEventMemoryOverhead> cached_overhead_estimate_;
+  TraceEvent chunk_[kTraceBufferChunkSize];
+  uint32 seq_;
+};
+
+// TraceBuffer holds the events as they are collected.
+class BASE_EXPORT TraceBuffer {
+ public:
+  virtual ~TraceBuffer() {}
+
+  virtual scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) = 0;
+  virtual void ReturnChunk(size_t index,
+                           scoped_ptr<TraceBufferChunk> chunk) = 0;
+
+  virtual bool IsFull() const = 0;
+  virtual size_t Size() const = 0;
+  virtual size_t Capacity() const = 0;
+  virtual TraceEvent* GetEventByHandle(TraceEventHandle handle) = 0;
+
+  // For iteration. Each TraceBuffer can only be iterated once.
+  virtual const TraceBufferChunk* NextChunk() = 0;
+
+  virtual scoped_ptr<TraceBuffer> CloneForIteration() const = 0;
+
+  // Computes an estimate of the size of the buffer, including all the retained
+  // objects.
+  virtual void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) = 0;
+
+  static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks);
+  static TraceBuffer* CreateTraceBufferVectorOfSize(size_t max_chunks);
+};
+
+// TraceResultBuffer collects and converts trace fragments returned by TraceLog
+// to JSON output.
+class BASE_EXPORT TraceResultBuffer {
+ public:
+  typedef base::Callback<void(const std::string&)> OutputCallback;
+
+  // If you don't need to stream JSON chunks out efficiently, and just want to
+  // get a complete JSON string after calling Finish, use this struct to collect
+  // JSON trace output.
+  struct BASE_EXPORT SimpleOutput {
+    OutputCallback GetCallback();
+    void Append(const std::string& json_string);
+
+    // Do what you want with the json_output_ string after calling
+    // TraceResultBuffer::Finish.
+    std::string json_output;
+  };
+
+  TraceResultBuffer();
+  ~TraceResultBuffer();
+
+  // Set callback. The callback will be called during Start with the initial
+  // JSON output and during AddFragment and Finish with following JSON output
+  // chunks. The callback target must live past the last calls to
+  // TraceResultBuffer::Start/AddFragment/Finish.
+  void SetOutputCallback(const OutputCallback& json_chunk_callback);
+
+  // Start JSON output. This resets all internal state, so you can reuse
+  // the TraceResultBuffer by calling Start.
+  void Start();
+
+  // Call AddFragment 0 or more times to add trace fragments from TraceLog.
+  void AddFragment(const std::string& trace_fragment);
+
+  // When all fragments have been added, call Finish to complete the JSON
+  // formatted output.
+  void Finish();
+
+ private:
+  OutputCallback output_callback_;
+  bool append_comma_;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_BUFFER_H_
diff --git a/base/trace_event/trace_config.cc b/base/trace_event/trace_config.cc
new file mode 100644
index 0000000..8d2c909
--- /dev/null
+++ b/base/trace_event/trace_config.cc
@@ -0,0 +1,669 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_config.h"
+
+#include <utility>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/strings/pattern.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// String options that can be used to initialize TraceOptions.
+const char kRecordUntilFull[] = "record-until-full";
+const char kRecordContinuously[] = "record-continuously";
+const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
+const char kTraceToConsole[] = "trace-to-console";
+const char kEnableSampling[] = "enable-sampling";
+const char kEnableSystrace[] = "enable-systrace";
+const char kEnableArgumentFilter[] = "enable-argument-filter";
+
+// String parameters that can be used to parse the trace config string.
+const char kRecordModeParam[] = "record_mode";
+const char kEnableSamplingParam[] = "enable_sampling";
+const char kEnableSystraceParam[] = "enable_systrace";
+const char kEnableArgumentFilterParam[] = "enable_argument_filter";
+const char kIncludedCategoriesParam[] = "included_categories";
+const char kExcludedCategoriesParam[] = "excluded_categories";
+const char kSyntheticDelaysParam[] = "synthetic_delays";
+
+const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY(";
+
+// String parameters that is used to parse memory dump config in trace config
+// string.
+const char kMemoryDumpConfigParam[] = "memory_dump_config";
+const char kTriggersParam[] = "triggers";
+const char kPeriodicIntervalParam[] = "periodic_interval_ms";
+const char kModeParam[] = "mode";
+
+// Default configuration of memory dumps.
+const TraceConfig::MemoryDumpTriggerConfig kDefaultHeavyMemoryDumpTrigger = {
+    2000,  // periodic_interval_ms
+    MemoryDumpLevelOfDetail::DETAILED};
+const TraceConfig::MemoryDumpTriggerConfig kDefaultLightMemoryDumpTrigger = {
+    250,  // periodic_interval_ms
+    MemoryDumpLevelOfDetail::LIGHT};
+
+class ConvertableTraceConfigToTraceFormat
+    : public base::trace_event::ConvertableToTraceFormat {
+ public:
+  explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
+      : trace_config_(trace_config) {}
+  void AppendAsTraceFormat(std::string* out) const override {
+    out->append(trace_config_.ToString());
+  }
+
+ protected:
+  ~ConvertableTraceConfigToTraceFormat() override {}
+
+ private:
+  const TraceConfig trace_config_;
+};
+
+}  // namespace
+
+TraceConfig::TraceConfig() {
+  InitializeDefault();
+}
+
+TraceConfig::TraceConfig(const std::string& category_filter_string,
+                         const std::string& trace_options_string) {
+  InitializeFromStrings(category_filter_string, trace_options_string);
+}
+
+TraceConfig::TraceConfig(const std::string& category_filter_string,
+                         TraceRecordMode record_mode) {
+  std::string trace_options_string;
+  switch (record_mode) {
+    case RECORD_UNTIL_FULL:
+      trace_options_string = kRecordUntilFull;
+      break;
+    case RECORD_CONTINUOUSLY:
+      trace_options_string = kRecordContinuously;
+      break;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      trace_options_string = kRecordAsMuchAsPossible;
+      break;
+    case ECHO_TO_CONSOLE:
+      trace_options_string = kTraceToConsole;
+      break;
+    default:
+      NOTREACHED();
+  }
+  InitializeFromStrings(category_filter_string, trace_options_string);
+}
+
+TraceConfig::TraceConfig(const std::string& config_string) {
+  if (!config_string.empty())
+    InitializeFromConfigString(config_string);
+  else
+    InitializeDefault();
+}
+
+TraceConfig::TraceConfig(const TraceConfig& tc)
+    : record_mode_(tc.record_mode_),
+      enable_sampling_(tc.enable_sampling_),
+      enable_systrace_(tc.enable_systrace_),
+      enable_argument_filter_(tc.enable_argument_filter_),
+      memory_dump_config_(tc.memory_dump_config_),
+      included_categories_(tc.included_categories_),
+      disabled_categories_(tc.disabled_categories_),
+      excluded_categories_(tc.excluded_categories_),
+      synthetic_delays_(tc.synthetic_delays_) {}
+
+TraceConfig::~TraceConfig() {
+}
+
+TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
+  if (this == &rhs)
+    return *this;
+
+  record_mode_ = rhs.record_mode_;
+  enable_sampling_ = rhs.enable_sampling_;
+  enable_systrace_ = rhs.enable_systrace_;
+  enable_argument_filter_ = rhs.enable_argument_filter_;
+  memory_dump_config_ = rhs.memory_dump_config_;
+  included_categories_ = rhs.included_categories_;
+  disabled_categories_ = rhs.disabled_categories_;
+  excluded_categories_ = rhs.excluded_categories_;
+  synthetic_delays_ = rhs.synthetic_delays_;
+  return *this;
+}
+
+const TraceConfig::StringList& TraceConfig::GetSyntheticDelayValues() const {
+  return synthetic_delays_;
+}
+
+std::string TraceConfig::ToString() const {
+  base::DictionaryValue dict;
+  ToDict(dict);
+
+  std::string json;
+  base::JSONWriter::Write(dict, &json);
+
+  return json;
+}
+
+scoped_refptr<ConvertableToTraceFormat>
+TraceConfig::AsConvertableToTraceFormat() const {
+  return new ConvertableTraceConfigToTraceFormat(*this);
+}
+
+std::string TraceConfig::ToCategoryFilterString() const {
+  std::string filter_string;
+  WriteCategoryFilterString(included_categories_, &filter_string, true);
+  WriteCategoryFilterString(disabled_categories_, &filter_string, true);
+  WriteCategoryFilterString(excluded_categories_, &filter_string, false);
+  WriteCategoryFilterString(synthetic_delays_, &filter_string);
+  return filter_string;
+}
+
+bool TraceConfig::IsCategoryGroupEnabled(
+    const char* category_group_name) const {
+  // TraceLog should call this method only as part of enabling/disabling
+  // categories.
+
+  bool had_enabled_by_default = false;
+  DCHECK(category_group_name);
+  CStringTokenizer category_group_tokens(
+      category_group_name, category_group_name + strlen(category_group_name),
+      ",");
+  while (category_group_tokens.GetNext()) {
+    std::string category_group_token = category_group_tokens.token();
+    // Don't allow empty tokens, nor tokens with leading or trailing space.
+    DCHECK(!TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+               category_group_token))
+        << "Disallowed category string";
+    if (IsCategoryEnabled(category_group_token.c_str())) {
+      return true;
+    }
+    if (!base::MatchPattern(category_group_token.c_str(),
+                            TRACE_DISABLED_BY_DEFAULT("*")))
+      had_enabled_by_default = true;
+  }
+  // Do a second pass to check for explicitly disabled categories
+  // (those explicitly enabled have priority due to first pass).
+  category_group_tokens.Reset();
+  bool category_group_disabled = false;
+  while (category_group_tokens.GetNext()) {
+    std::string category_group_token = category_group_tokens.token();
+    for (StringList::const_iterator ci = excluded_categories_.begin();
+         ci != excluded_categories_.end();
+         ++ci) {
+      if (base::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, if it's not a disabled-by-default category,
+      // it has to be included_ list. Enable the category_group_name
+      // for recording.
+      if (!base::MatchPattern(category_group_token.c_str(),
+                              TRACE_DISABLED_BY_DEFAULT("*"))) {
+        category_group_disabled = false;
+      }
+    }
+    // One of the categories present in category_group_name is not present in
+    // excluded_ list. Implies this category_group_name group can be enabled
+    // for recording, since one of its groups is enabled for recording.
+    if (!category_group_disabled)
+      break;
+  }
+  // If the category group is not excluded, and there are no included patterns
+  // we consider this category group enabled, as long as it had categories
+  // other than disabled-by-default.
+  return !category_group_disabled &&
+         included_categories_.empty() && had_enabled_by_default;
+}
+
+void TraceConfig::Merge(const TraceConfig& config) {
+  if (record_mode_ != config.record_mode_
+      || enable_sampling_ != config.enable_sampling_
+      || enable_systrace_ != config.enable_systrace_
+      || enable_argument_filter_ != config.enable_argument_filter_) {
+    DLOG(ERROR) << "Attempting to merge trace config with a different "
+                << "set of options.";
+  }
+
+  // Keep included patterns only if both filters have an included entry.
+  // Otherwise, one of the filter was specifying "*" and we want to honor the
+  // broadest filter.
+  if (HasIncludedPatterns() && config.HasIncludedPatterns()) {
+    included_categories_.insert(included_categories_.end(),
+                                config.included_categories_.begin(),
+                                config.included_categories_.end());
+  } else {
+    included_categories_.clear();
+  }
+
+  memory_dump_config_.insert(memory_dump_config_.end(),
+                             config.memory_dump_config_.begin(),
+                             config.memory_dump_config_.end());
+
+  disabled_categories_.insert(disabled_categories_.end(),
+                              config.disabled_categories_.begin(),
+                              config.disabled_categories_.end());
+  excluded_categories_.insert(excluded_categories_.end(),
+                              config.excluded_categories_.begin(),
+                              config.excluded_categories_.end());
+  synthetic_delays_.insert(synthetic_delays_.end(),
+                           config.synthetic_delays_.begin(),
+                           config.synthetic_delays_.end());
+}
+
+void TraceConfig::Clear() {
+  record_mode_ = RECORD_UNTIL_FULL;
+  enable_sampling_ = false;
+  enable_systrace_ = false;
+  enable_argument_filter_ = false;
+  included_categories_.clear();
+  disabled_categories_.clear();
+  excluded_categories_.clear();
+  synthetic_delays_.clear();
+  memory_dump_config_.clear();
+}
+
+void TraceConfig::InitializeDefault() {
+  record_mode_ = RECORD_UNTIL_FULL;
+  enable_sampling_ = false;
+  enable_systrace_ = false;
+  enable_argument_filter_ = false;
+  excluded_categories_.push_back("*Debug");
+  excluded_categories_.push_back("*Test");
+}
+
+void TraceConfig::InitializeFromConfigString(const std::string& config_string) {
+  scoped_ptr<base::Value> value(base::JSONReader::Read(config_string));
+  if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) {
+    InitializeDefault();
+    return;
+  }
+  scoped_ptr<base::DictionaryValue> dict(
+        static_cast<base::DictionaryValue*>(value.release()));
+
+  record_mode_ = RECORD_UNTIL_FULL;
+  std::string record_mode;
+  if (dict->GetString(kRecordModeParam, &record_mode)) {
+    if (record_mode == kRecordUntilFull) {
+      record_mode_ = RECORD_UNTIL_FULL;
+    } else if (record_mode == kRecordContinuously) {
+      record_mode_ = RECORD_CONTINUOUSLY;
+    } else if (record_mode == kTraceToConsole) {
+      record_mode_ = ECHO_TO_CONSOLE;
+    } else if (record_mode == kRecordAsMuchAsPossible) {
+      record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
+    }
+  }
+
+  bool enable_sampling;
+  if (!dict->GetBoolean(kEnableSamplingParam, &enable_sampling))
+    enable_sampling_ = false;
+  else
+    enable_sampling_ = enable_sampling;
+
+  bool enable_systrace;
+  if (!dict->GetBoolean(kEnableSystraceParam, &enable_systrace))
+    enable_systrace_ = false;
+  else
+    enable_systrace_ = enable_systrace;
+
+  bool enable_argument_filter;
+  if (!dict->GetBoolean(kEnableArgumentFilterParam, &enable_argument_filter))
+    enable_argument_filter_ = false;
+  else
+    enable_argument_filter_ = enable_argument_filter;
+
+  base::ListValue* category_list = nullptr;
+  if (dict->GetList(kIncludedCategoriesParam, &category_list))
+    SetCategoriesFromIncludedList(*category_list);
+  if (dict->GetList(kExcludedCategoriesParam, &category_list))
+    SetCategoriesFromExcludedList(*category_list);
+  if (dict->GetList(kSyntheticDelaysParam, &category_list))
+    SetSyntheticDelaysFromList(*category_list);
+
+  if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
+    // If dump triggers not set, the client is using the legacy with just
+    // category enabled. So, use the default periodic dump config.
+    base::DictionaryValue* memory_dump_config = nullptr;
+    if (dict->GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
+      SetMemoryDumpConfig(*memory_dump_config);
+    else
+      SetDefaultMemoryDumpConfig();
+  }
+}
+
+void TraceConfig::InitializeFromStrings(
+    const std::string& category_filter_string,
+    const std::string& trace_options_string) {
+  if (!category_filter_string.empty()) {
+    std::vector<std::string> split = base::SplitString(
+        category_filter_string, ",", base::TRIM_WHITESPACE,
+        base::SPLIT_WANT_ALL);
+    std::vector<std::string>::iterator iter;
+    for (iter = split.begin(); iter != split.end(); ++iter) {
+      std::string category = *iter;
+      // Ignore empty categories.
+      if (category.empty())
+        continue;
+      // Synthetic delays are of the form 'DELAY(delay;option;option;...)'.
+      if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 &&
+          category.at(category.size() - 1) == ')') {
+        category = category.substr(
+            strlen(kSyntheticDelayCategoryFilterPrefix),
+            category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1);
+        size_t name_length = category.find(';');
+        if (name_length != std::string::npos && name_length > 0 &&
+            name_length != category.size() - 1) {
+          synthetic_delays_.push_back(category);
+        }
+      } else if (category.at(0) == '-') {
+        // Excluded categories start with '-'.
+        // Remove '-' from category string.
+        category = category.substr(1);
+        excluded_categories_.push_back(category);
+      } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
+                                  TRACE_DISABLED_BY_DEFAULT("")) == 0) {
+        disabled_categories_.push_back(category);
+      } else {
+        included_categories_.push_back(category);
+      }
+    }
+  }
+
+  record_mode_ = RECORD_UNTIL_FULL;
+  enable_sampling_ = false;
+  enable_systrace_ = false;
+  enable_argument_filter_ = false;
+  if(!trace_options_string.empty()) {
+    std::vector<std::string> split = base::SplitString(
+        trace_options_string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+    std::vector<std::string>::iterator iter;
+    for (iter = split.begin(); iter != split.end(); ++iter) {
+      if (*iter == kRecordUntilFull) {
+        record_mode_ = RECORD_UNTIL_FULL;
+      } else if (*iter == kRecordContinuously) {
+        record_mode_ = RECORD_CONTINUOUSLY;
+      } else if (*iter == kTraceToConsole) {
+        record_mode_ = ECHO_TO_CONSOLE;
+      } else if (*iter == kRecordAsMuchAsPossible) {
+        record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
+      } else if (*iter == kEnableSampling) {
+        enable_sampling_ = true;
+      } else if (*iter == kEnableSystrace) {
+        enable_systrace_ = true;
+      } else if (*iter == kEnableArgumentFilter) {
+        enable_argument_filter_ = true;
+      }
+    }
+  }
+
+  if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
+    SetDefaultMemoryDumpConfig();
+  }
+}
+
+void TraceConfig::SetCategoriesFromIncludedList(
+    const base::ListValue& included_list) {
+  included_categories_.clear();
+  for (size_t i = 0; i < included_list.GetSize(); ++i) {
+    std::string category;
+    if (!included_list.GetString(i, &category))
+      continue;
+    if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
+                         TRACE_DISABLED_BY_DEFAULT("")) == 0) {
+      disabled_categories_.push_back(category);
+    } else {
+      included_categories_.push_back(category);
+    }
+  }
+}
+
+void TraceConfig::SetCategoriesFromExcludedList(
+    const base::ListValue& excluded_list) {
+  excluded_categories_.clear();
+  for (size_t i = 0; i < excluded_list.GetSize(); ++i) {
+    std::string category;
+    if (excluded_list.GetString(i, &category))
+      excluded_categories_.push_back(category);
+  }
+}
+
+void TraceConfig::SetSyntheticDelaysFromList(const base::ListValue& list) {
+  synthetic_delays_.clear();
+  for (size_t i = 0; i < list.GetSize(); ++i) {
+    std::string delay;
+    if (!list.GetString(i, &delay))
+      continue;
+    // Synthetic delays are of the form "delay;option;option;...".
+    size_t name_length = delay.find(';');
+    if (name_length != std::string::npos && name_length > 0 &&
+        name_length != delay.size() - 1) {
+      synthetic_delays_.push_back(delay);
+    }
+  }
+}
+
+void TraceConfig::AddCategoryToDict(base::DictionaryValue& dict,
+                                    const char* param,
+                                    const StringList& categories) const {
+  if (categories.empty())
+    return;
+
+  scoped_ptr<base::ListValue> list(new base::ListValue());
+  for (StringList::const_iterator ci = categories.begin();
+       ci != categories.end();
+       ++ci) {
+    list->AppendString(*ci);
+  }
+
+  dict.Set(param, std::move(list));
+}
+
+void TraceConfig::SetMemoryDumpConfig(
+    const base::DictionaryValue& memory_dump_config) {
+  memory_dump_config_.clear();
+
+  const base::ListValue* trigger_list = nullptr;
+  if (!memory_dump_config.GetList(kTriggersParam, &trigger_list) ||
+      trigger_list->GetSize() == 0) {
+    return;
+  }
+
+  for (size_t i = 0; i < trigger_list->GetSize(); ++i) {
+    const base::DictionaryValue* trigger = nullptr;
+    if (!trigger_list->GetDictionary(i, &trigger))
+      continue;
+
+    MemoryDumpTriggerConfig dump_config;
+    int interval = 0;
+
+    if (!trigger->GetInteger(kPeriodicIntervalParam, &interval)) {
+      continue;
+    }
+    DCHECK_GT(interval, 0);
+    dump_config.periodic_interval_ms = static_cast<uint32>(interval);
+    std::string level_of_detail_str;
+    trigger->GetString(kModeParam, &level_of_detail_str);
+    dump_config.level_of_detail =
+        StringToMemoryDumpLevelOfDetail(level_of_detail_str);
+    memory_dump_config_.push_back(dump_config);
+  }
+}
+
+void TraceConfig::SetDefaultMemoryDumpConfig() {
+  memory_dump_config_.clear();
+  memory_dump_config_.push_back(kDefaultHeavyMemoryDumpTrigger);
+  memory_dump_config_.push_back(kDefaultLightMemoryDumpTrigger);
+}
+
+void TraceConfig::ToDict(base::DictionaryValue& dict) const {
+  switch (record_mode_) {
+    case RECORD_UNTIL_FULL:
+      dict.SetString(kRecordModeParam, kRecordUntilFull);
+      break;
+    case RECORD_CONTINUOUSLY:
+      dict.SetString(kRecordModeParam, kRecordContinuously);
+      break;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      dict.SetString(kRecordModeParam, kRecordAsMuchAsPossible);
+      break;
+    case ECHO_TO_CONSOLE:
+      dict.SetString(kRecordModeParam, kTraceToConsole);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  if (enable_sampling_)
+    dict.SetBoolean(kEnableSamplingParam, true);
+  else
+    dict.SetBoolean(kEnableSamplingParam, false);
+
+  if (enable_systrace_)
+    dict.SetBoolean(kEnableSystraceParam, true);
+  else
+    dict.SetBoolean(kEnableSystraceParam, false);
+
+  if (enable_argument_filter_)
+    dict.SetBoolean(kEnableArgumentFilterParam, true);
+  else
+    dict.SetBoolean(kEnableArgumentFilterParam, false);
+
+  StringList categories(included_categories_);
+  categories.insert(categories.end(),
+                    disabled_categories_.begin(),
+                    disabled_categories_.end());
+  AddCategoryToDict(dict, kIncludedCategoriesParam, categories);
+  AddCategoryToDict(dict, kExcludedCategoriesParam, excluded_categories_);
+  AddCategoryToDict(dict, kSyntheticDelaysParam, synthetic_delays_);
+
+  if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
+    scoped_ptr<base::DictionaryValue> memory_dump_config(
+        new base::DictionaryValue());
+    scoped_ptr<base::ListValue> triggers_list(new base::ListValue());
+    for (const MemoryDumpTriggerConfig& config : memory_dump_config_) {
+      scoped_ptr<base::DictionaryValue> trigger_dict(
+          new base::DictionaryValue());
+      trigger_dict->SetInteger(kPeriodicIntervalParam,
+                               static_cast<int>(config.periodic_interval_ms));
+      trigger_dict->SetString(
+          kModeParam, MemoryDumpLevelOfDetailToString(config.level_of_detail));
+      triggers_list->Append(std::move(trigger_dict));
+    }
+
+    // Empty triggers will still be specified explicitly since it means that
+    // the periodic dumps are not enabled.
+    memory_dump_config->Set(kTriggersParam, std::move(triggers_list));
+    dict.Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
+  }
+}
+
+std::string TraceConfig::ToTraceOptionsString() const {
+  std::string ret;
+  switch (record_mode_) {
+    case RECORD_UNTIL_FULL:
+      ret = kRecordUntilFull;
+      break;
+    case RECORD_CONTINUOUSLY:
+      ret = kRecordContinuously;
+      break;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      ret = kRecordAsMuchAsPossible;
+      break;
+    case ECHO_TO_CONSOLE:
+      ret = kTraceToConsole;
+      break;
+    default:
+      NOTREACHED();
+  }
+  if (enable_sampling_)
+    ret = ret + "," + kEnableSampling;
+  if (enable_systrace_)
+    ret = ret + "," + kEnableSystrace;
+  if (enable_argument_filter_)
+    ret = ret + "," + kEnableArgumentFilter;
+  return ret;
+}
+
+void TraceConfig::WriteCategoryFilterString(const StringList& values,
+                                            std::string* out,
+                                            bool included) const {
+  bool prepend_comma = !out->empty();
+  int token_cnt = 0;
+  for (StringList::const_iterator ci = values.begin();
+       ci != values.end(); ++ci) {
+    if (token_cnt > 0 || prepend_comma)
+      StringAppendF(out, ",");
+    StringAppendF(out, "%s%s", (included ? "" : "-"), ci->c_str());
+    ++token_cnt;
+  }
+}
+
+void TraceConfig::WriteCategoryFilterString(const StringList& delays,
+                                            std::string* out) const {
+  bool prepend_comma = !out->empty();
+  int token_cnt = 0;
+  for (StringList::const_iterator ci = delays.begin();
+       ci != delays.end(); ++ci) {
+    if (token_cnt > 0 || prepend_comma)
+      StringAppendF(out, ",");
+    StringAppendF(out, "%s%s)", kSyntheticDelayCategoryFilterPrefix,
+                  ci->c_str());
+    ++token_cnt;
+  }
+}
+
+bool TraceConfig::IsCategoryEnabled(const char* category_name) const {
+  StringList::const_iterator ci;
+
+  // Check the disabled- filters and the disabled-* wildcard first so that a
+  // "*" filter does not include the disabled.
+  for (ci = disabled_categories_.begin();
+       ci != disabled_categories_.end();
+       ++ci) {
+    if (base::MatchPattern(category_name, ci->c_str()))
+      return true;
+  }
+
+  if (base::MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
+    return false;
+
+  for (ci = included_categories_.begin();
+       ci != included_categories_.end();
+       ++ci) {
+    if (base::MatchPattern(category_name, ci->c_str()))
+      return true;
+  }
+
+  return false;
+}
+
+bool TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+    const std::string& str) {
+  return  str.empty() ||
+          str.at(0) == ' ' ||
+          str.at(str.length() - 1) == ' ';
+}
+
+bool TraceConfig::HasIncludedPatterns() const {
+  return !included_categories_.empty();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h
new file mode 100644
index 0000000..e7a1ab5
--- /dev/null
+++ b/base/trace_event/trace_config.h
@@ -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.
+
+#ifndef BASE_TRACE_EVENT_TRACE_CONFIG_H_
+#define BASE_TRACE_EVENT_TRACE_CONFIG_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+class ConvertableToTraceFormat;
+
+// Options determines how the trace buffer stores data.
+enum TraceRecordMode {
+  // Record until the trace buffer is full.
+  RECORD_UNTIL_FULL,
+
+  // Record until the user ends the trace. The trace buffer is a fixed size
+  // and we use it as a ring buffer during recording.
+  RECORD_CONTINUOUSLY,
+
+  // Record until the trace buffer is full, but with a huge buffer size.
+  RECORD_AS_MUCH_AS_POSSIBLE,
+
+  // Echo to console. Events are discarded.
+  ECHO_TO_CONSOLE,
+};
+
+class BASE_EXPORT TraceConfig {
+ public:
+  typedef std::vector<std::string> StringList;
+
+  // Specifies the memory dump config for tracing. Used only when
+  // "memory-infra" category is enabled.
+  struct MemoryDumpTriggerConfig {
+    uint32 periodic_interval_ms;
+    MemoryDumpLevelOfDetail level_of_detail;
+  };
+
+  typedef std::vector<MemoryDumpTriggerConfig> MemoryDumpConfig;
+
+  TraceConfig();
+
+  // Create TraceConfig object from category filter and trace options strings.
+  //
+  // |category_filter_string| is a comma-delimited list of category wildcards.
+  // A category can have an optional '-' prefix to make it an excluded category.
+  // All the same rules apply above, so for example, having both included and
+  // excluded categories in the same list would not be supported.
+  //
+  // Category filters can also be used to configure synthetic delays.
+  //
+  // |trace_options_string| is a comma-delimited list of trace options.
+  // Possible options are: "record-until-full", "record-continuously",
+  // "record-as-much-as-possible", "trace-to-console", "enable-sampling",
+  // "enable-systrace" and "enable-argument-filter".
+  // The first 4 options are trace recoding modes and hence
+  // mutually exclusive. If more than one trace recording modes appear in the
+  // options_string, the last one takes precedence. If none of the trace
+  // recording mode is specified, recording mode is RECORD_UNTIL_FULL.
+  //
+  // The trace option will first be reset to the default option
+  // (record_mode set to RECORD_UNTIL_FULL, enable_sampling, enable_systrace,
+  // and enable_argument_filter set to false) before options parsed from
+  // |trace_options_string| are applied on it. If |trace_options_string| is
+  // invalid, the final state of trace options is undefined.
+  //
+  // Example: TraceConfig("test_MyTest*", "record-until-full");
+  // Example: TraceConfig("test_MyTest*,test_OtherStuff",
+  //                      "record-continuously, enable-sampling");
+  // Example: TraceConfig("-excluded_category1,-excluded_category2",
+  //                      "record-until-full, trace-to-console");
+  //          would set ECHO_TO_CONSOLE as the recording mode.
+  // Example: TraceConfig("-*,webkit", "");
+  //          would disable everything but webkit; and use default options.
+  // Example: TraceConfig("-webkit", "");
+  //          would enable everything but webkit; and use default options.
+  // Example: TraceConfig("DELAY(gpu.PresentingFrame;16)", "");
+  //          would make swap buffers always take at least 16 ms; and use
+  //          default options.
+  // Example: TraceConfig("DELAY(gpu.PresentingFrame;16;oneshot)", "");
+  //          would make swap buffers take at least 16 ms the first time it is
+  //          called; and use default options.
+  // Example: TraceConfig("DELAY(gpu.PresentingFrame;16;alternating)", "");
+  //          would make swap buffers take at least 16 ms every other time it
+  //          is called; and use default options.
+  TraceConfig(const std::string& category_filter_string,
+              const std::string& trace_options_string);
+
+  TraceConfig(const std::string& category_filter_string,
+              TraceRecordMode record_mode);
+
+  // Create TraceConfig object from the trace config string.
+  //
+  // |config_string| is a dictionary formatted as a JSON string, containing both
+  // category filters and trace options.
+  //
+  // Example:
+  //   {
+  //     "record_mode": "record-continuously",
+  //     "enable_sampling": true,
+  //     "enable_systrace": true,
+  //     "enable_argument_filter": true,
+  //     "included_categories": ["included",
+  //                             "inc_pattern*",
+  //                             "disabled-by-default-memory-infra"],
+  //     "excluded_categories": ["excluded", "exc_pattern*"],
+  //     "synthetic_delays": ["test.Delay1;16", "test.Delay2;32"]
+  //     "memory_dump_config": {
+  //       "triggers": [
+  //         {
+  //           "mode": "detailed",
+  //           "periodic_interval_ms": 2000
+  //         }
+  //       ]
+  //     }
+  //   }
+  //
+  // Note: memory_dump_config can be specified only if
+  // disabled-by-default-memory-infra category is enabled.
+  explicit TraceConfig(const std::string& config_string);
+
+  TraceConfig(const TraceConfig& tc);
+
+  ~TraceConfig();
+
+  TraceConfig& operator=(const TraceConfig& rhs);
+
+  // Return a list of the synthetic delays specified in this category filter.
+  const StringList& GetSyntheticDelayValues() const;
+
+  TraceRecordMode GetTraceRecordMode() const { return record_mode_; }
+  bool IsSamplingEnabled() const { return enable_sampling_; }
+  bool IsSystraceEnabled() const { return enable_systrace_; }
+  bool IsArgumentFilterEnabled() const { return enable_argument_filter_; }
+
+  void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; }
+  void EnableSampling() { enable_sampling_ = true; }
+  void EnableSystrace() { enable_systrace_ = true; }
+  void EnableArgumentFilter() { enable_argument_filter_ = true; }
+
+  // Writes the string representation of the TraceConfig. The string is JSON
+  // formatted.
+  std::string ToString() const;
+
+  // Returns a scoped_refptr and wrap TraceConfig in ConvertableToTraceFormat
+  scoped_refptr<ConvertableToTraceFormat> AsConvertableToTraceFormat() const;
+
+  // Write the string representation of the CategoryFilter part.
+  std::string ToCategoryFilterString() const;
+
+  // Returns true if at least one category in the list is enabled by this
+  // trace config.
+  bool IsCategoryGroupEnabled(const char* category_group) const;
+
+  // Merges config with the current TraceConfig
+  void Merge(const TraceConfig& config);
+
+  void Clear();
+
+  const MemoryDumpConfig& memory_dump_config() const {
+    return memory_dump_config_;
+  }
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromValidLegacyFormat);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
+                           TraceConfigFromInvalidLegacyStrings);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, ConstructDefaultTraceConfig);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromValidString);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromInvalidString);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
+                           IsEmptyOrContainsLeadingOrTrailingWhitespace);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromMemoryConfigString);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, LegacyStringToMemoryDumpConfig);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, EmptyMemoryDumpConfigTest);
+
+  // The default trace config, used when none is provided.
+  // Allows all non-disabled-by-default categories through, except if they end
+  // in the suffix 'Debug' or 'Test'.
+  void InitializeDefault();
+
+  // Initialize from the config string
+  void InitializeFromConfigString(const std::string& config_string);
+
+  // Initialize from category filter and trace options strings
+  void InitializeFromStrings(const std::string& category_filter_string,
+                             const std::string& trace_options_string);
+
+  void SetCategoriesFromIncludedList(const base::ListValue& included_list);
+  void SetCategoriesFromExcludedList(const base::ListValue& excluded_list);
+  void SetSyntheticDelaysFromList(const base::ListValue& list);
+  void AddCategoryToDict(base::DictionaryValue& dict,
+                         const char* param,
+                         const StringList& categories) const;
+
+  void SetMemoryDumpConfig(const base::DictionaryValue& memory_dump_config);
+  void SetDefaultMemoryDumpConfig();
+
+  // Convert TraceConfig to the dict representation of the TraceConfig.
+  void ToDict(base::DictionaryValue& dict) const;
+
+  std::string ToTraceOptionsString() const;
+
+  void WriteCategoryFilterString(const StringList& values,
+                                 std::string* out,
+                                 bool included) const;
+  void WriteCategoryFilterString(const StringList& delays,
+                                 std::string* out) const;
+
+  // Returns true if category is enable according to this trace config.
+  bool IsCategoryEnabled(const char* category_name) const;
+
+  static bool IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      const std::string& str);
+
+  bool HasIncludedPatterns() const;
+
+  TraceRecordMode record_mode_;
+  bool enable_sampling_ : 1;
+  bool enable_systrace_ : 1;
+  bool enable_argument_filter_ : 1;
+
+  MemoryDumpConfig memory_dump_config_;
+
+  StringList included_categories_;
+  StringList disabled_categories_;
+  StringList excluded_categories_;
+  StringList synthetic_delays_;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_CONFIG_H_
diff --git a/base/trace_event/trace_config_memory_test_util.h b/base/trace_event/trace_config_memory_test_util.h
new file mode 100644
index 0000000..8d8206f
--- /dev/null
+++ b/base/trace_event/trace_config_memory_test_util.h
@@ -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.
+
+#ifndef BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
+#define BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceConfigMemoryTestUtil {
+ public:
+  static std::string GetTraceConfig_PeriodicTriggers(int light_period,
+                                                     int heavy_period) {
+    return StringPrintf(
+        "{"
+          "\"enable_argument_filter\":false,"
+          "\"enable_sampling\":false,"
+          "\"enable_systrace\":false,"
+          "\"included_categories\":["
+            "\"%s\""
+          "],"
+          "\"memory_dump_config\":{"
+            "\"triggers\":["
+              "{"
+                "\"mode\":\"light\","
+                "\"periodic_interval_ms\":%d"
+              "},"
+              "{"
+                "\"mode\":\"detailed\","
+                "\"periodic_interval_ms\":%d"
+              "}"
+            "]"
+          "},"
+          "\"record_mode\":\"record-until-full\""
+        "}", MemoryDumpManager::kTraceCategory, light_period, heavy_period);
+  }
+
+  static std::string GetTraceConfig_EmptyTriggers() {
+    return StringPrintf(
+        "{"
+          "\"enable_argument_filter\":false,"
+          "\"enable_sampling\":false,"
+          "\"enable_systrace\":false,"
+          "\"included_categories\":["
+            "\"%s\""
+          "],"
+          "\"memory_dump_config\":{"
+            "\"triggers\":["
+            "]"
+          "},"
+          "\"record_mode\":\"record-until-full\""
+        "}", MemoryDumpManager::kTraceCategory);
+  }
+
+  static std::string GetTraceConfig_NoTriggers() {
+    return StringPrintf(
+        "{"
+          "\"enable_argument_filter\":false,"
+          "\"enable_sampling\":false,"
+          "\"enable_systrace\":false,"
+          "\"included_categories\":["
+            "\"%s\""
+          "],"
+          "\"record_mode\":\"record-until-full\""
+        "}", MemoryDumpManager::kTraceCategory);
+  }
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
diff --git a/base/trace_event/trace_config_unittest.cc b/base/trace_event/trace_config_unittest.cc
new file mode 100644
index 0000000..1d88891
--- /dev/null
+++ b/base/trace_event/trace_config_unittest.cc
@@ -0,0 +1,531 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_config_memory_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+const char kDefaultTraceConfigString[] =
+  "{"
+    "\"enable_argument_filter\":false,"
+    "\"enable_sampling\":false,"
+    "\"enable_systrace\":false,"
+    "\"excluded_categories\":[\"*Debug\",\"*Test\"],"
+    "\"record_mode\":\"record-until-full\""
+  "}";
+}  // namespace
+
+TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
+  // From trace options strings
+  TraceConfig config("", "record-until-full");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "record-continuously");
+  EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "trace-to-console");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "record-as-much-as-possible");
+  EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-as-much-as-possible",
+               config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "record-until-full, enable-sampling");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_TRUE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-until-full,enable-sampling",
+               config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "enable-systrace, record-continuously");
+  EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-continuously,enable-systrace",
+               config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "enable-argument-filter,record-as-much-as-possible");
+  EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_TRUE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-as-much-as-possible,enable-argument-filter",
+               config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig(
+    "",
+    "enable-systrace,trace-to-console,enable-sampling,enable-argument-filter");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_TRUE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_TRUE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ(
+    "trace-to-console,enable-sampling,enable-systrace,enable-argument-filter",
+    config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig(
+    "", "record-continuously, record-until-full, trace-to-console");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
+
+  // From TraceRecordMode
+  config = TraceConfig("", RECORD_UNTIL_FULL);
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", RECORD_CONTINUOUSLY);
+  EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", ECHO_TO_CONSOLE);
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", RECORD_AS_MUCH_AS_POSSIBLE);
+  EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-as-much-as-possible",
+               config.ToTraceOptionsString().c_str());
+
+  // From category filter strings
+  config = TraceConfig("-*Debug,-*Test", "");
+  EXPECT_STREQ("-*Debug,-*Test", config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*", "");
+  EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
+               config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("only_inc_cat", "");
+  EXPECT_STREQ("only_inc_cat", config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("-only_exc_cat", "");
+  EXPECT_STREQ("-only_exc_cat", config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("disabled-by-default-cc,-excluded", "");
+  EXPECT_STREQ("disabled-by-default-cc,-excluded",
+               config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("disabled-by-default-cc,included", "");
+  EXPECT_STREQ("included,disabled-by-default-cc",
+               config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("DELAY(test.Delay1;16),included", "");
+  EXPECT_STREQ("included,DELAY(test.Delay1;16)",
+               config.ToCategoryFilterString().c_str());
+
+  // From both trace options and category filter strings
+  config = TraceConfig("", "");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("", config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*",
+                       "enable-systrace, trace-to-console, enable-sampling");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_TRUE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
+               config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("trace-to-console,enable-sampling,enable-systrace",
+               config.ToTraceOptionsString().c_str());
+
+  // From both trace options and category filter strings with spaces.
+  config = TraceConfig(" included , -excluded, inc_pattern*, ,-exc_pattern*   ",
+                       "enable-systrace, ,trace-to-console, enable-sampling  ");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_TRUE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
+               config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("trace-to-console,enable-sampling,enable-systrace",
+               config.ToTraceOptionsString().c_str());
+
+  // From category filter string and TraceRecordMode
+  config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*",
+                       RECORD_CONTINUOUSLY);
+  EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
+               config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
+}
+
+TEST(TraceConfigTest, TraceConfigFromInvalidLegacyStrings) {
+  TraceConfig config("", "foo-bar-baz");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("", config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("arbitrary-category", "foo-bar-baz, enable-systrace");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("arbitrary-category", config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("record-until-full,enable-systrace",
+               config.ToTraceOptionsString().c_str());
+
+  const char* const configs[] = {
+    "",
+    "DELAY(",
+    "DELAY(;",
+    "DELAY(;)",
+    "DELAY(test.Delay)",
+    "DELAY(test.Delay;)"
+  };
+  for (size_t i = 0; i < arraysize(configs); i++) {
+    TraceConfig tc(configs[i], "");
+    EXPECT_EQ(0u, tc.GetSyntheticDelayValues().size());
+  }
+}
+
+TEST(TraceConfigTest, ConstructDefaultTraceConfig) {
+  // Make sure that upon an empty string, we fall back to the default config.
+  TraceConfig tc;
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  EXPECT_FALSE(tc.IsCategoryEnabled("Category1"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("not-excluded-category"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("CategoryTest"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("CategoryDebug"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("disabled-by-default-cc"));
+
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("not-excluded-category"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("CategoryTest"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("CategoryDebug"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
+
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,CategoryDebug"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("CategoryDebug,Category1"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("CategoryTest,not-excluded-category"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("CategoryDebug,CategoryTest"));
+}
+
+TEST(TraceConfigTest, TraceConfigFromValidString) {
+  // Using some non-empty config string.
+  const char config_string[] =
+    "{"
+      "\"enable_argument_filter\":true,"
+      "\"enable_sampling\":true,"
+      "\"enable_systrace\":true,"
+      "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
+      "\"included_categories\":[\"included\","
+                               "\"inc_pattern*\","
+                               "\"disabled-by-default-cc\"],"
+      "\"record_mode\":\"record-continuously\","
+      "\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
+    "}";
+  TraceConfig tc(config_string);
+
+  EXPECT_STREQ(config_string, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_CONTINUOUSLY, tc.GetTraceRecordMode());
+  EXPECT_TRUE(tc.IsSamplingEnabled());
+  EXPECT_TRUE(tc.IsSystraceEnabled());
+  EXPECT_TRUE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("included,inc_pattern*,disabled-by-default-cc,-excluded,"
+               "-exc_pattern*,DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
+               tc.ToCategoryFilterString().c_str());
+
+  EXPECT_TRUE(tc.IsCategoryEnabled("included"));
+  EXPECT_TRUE(tc.IsCategoryEnabled("inc_pattern_category"));
+  EXPECT_TRUE(tc.IsCategoryEnabled("disabled-by-default-cc"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("excluded"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("exc_pattern_category"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("disabled-by-default-others"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("not-excluded-nor-included"));
+
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("inc_pattern_category"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("exc_pattern_category"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-others"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("not-excluded-nor-included"));
+
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("included,excluded"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,exc_pattern_category"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("included,DELAY(test.Delay1;16)"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("DELAY(test.Delay1;16)"));
+
+  EXPECT_EQ(2u, tc.GetSyntheticDelayValues().size());
+  EXPECT_STREQ("test.Delay1;16", tc.GetSyntheticDelayValues()[0].c_str());
+  EXPECT_STREQ("test.Delay2;32", tc.GetSyntheticDelayValues()[1].c_str());
+
+  const char config_string_2[] = "{\"included_categories\":[\"*\"]}";
+  TraceConfig tc2(config_string_2);
+  EXPECT_TRUE(tc2.IsCategoryEnabled("non-disabled-by-default-pattern"));
+  EXPECT_FALSE(tc2.IsCategoryEnabled("disabled-by-default-pattern"));
+  EXPECT_TRUE(tc2.IsCategoryGroupEnabled("non-disabled-by-default-pattern"));
+  EXPECT_FALSE(tc2.IsCategoryGroupEnabled("disabled-by-default-pattern"));
+
+  // Clear
+  tc.Clear();
+  EXPECT_STREQ(tc.ToString().c_str(),
+               "{"
+                 "\"enable_argument_filter\":false,"
+                 "\"enable_sampling\":false,"
+                 "\"enable_systrace\":false,"
+                 "\"record_mode\":\"record-until-full\""
+               "}");
+}
+
+TEST(TraceConfigTest, TraceConfigFromInvalidString) {
+  // The config string needs to be a dictionary correctly formatted as a JSON
+  // string. Otherwise, it will fall back to the default initialization.
+  TraceConfig tc("");
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  tc = TraceConfig("This is an invalid config string.");
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  tc = TraceConfig("[\"This\", \"is\", \"not\", \"a\", \"dictionary\"]");
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  tc = TraceConfig("{\"record_mode\": invalid-value-needs-double-quote}");
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  // If the config string a dictionary formatted as a JSON string, it will
+  // initialize TraceConfig with best effort.
+  tc = TraceConfig("{}");
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
+
+  tc = TraceConfig("{\"arbitrary-key\":\"arbitrary-value\"}");
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
+
+  const char invalid_config_string[] =
+    "{"
+      "\"enable_sampling\":\"true\","
+      "\"enable_systrace\":1,"
+      "\"excluded_categories\":[\"excluded\"],"
+      "\"included_categories\":\"not a list\","
+      "\"record_mode\":\"arbitrary-mode\","
+      "\"synthetic_delays\":[\"test.Delay1;16\","
+                            "\"invalid-delay\","
+                            "\"test.Delay2;32\"]"
+    "}";
+  tc = TraceConfig(invalid_config_string);
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-excluded,DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
+               tc.ToCategoryFilterString().c_str());
+
+  const char invalid_config_string_2[] =
+    "{"
+      "\"included_categories\":[\"category\",\"disabled-by-default-pattern\"],"
+      "\"excluded_categories\":[\"category\",\"disabled-by-default-pattern\"]"
+    "}";
+  tc = TraceConfig(invalid_config_string_2);
+  EXPECT_TRUE(tc.IsCategoryEnabled("category"));
+  EXPECT_TRUE(tc.IsCategoryEnabled("disabled-by-default-pattern"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("category"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-pattern"));
+}
+
+TEST(TraceConfigTest, MergingTraceConfigs) {
+  // Merge
+  TraceConfig tc;
+  TraceConfig tc2("included,-excluded,inc_pattern*,-exc_pattern*", "");
+  tc.Merge(tc2);
+  EXPECT_STREQ("{"
+                 "\"enable_argument_filter\":false,"
+                 "\"enable_sampling\":false,"
+                 "\"enable_systrace\":false,"
+                 "\"excluded_categories\":["
+                   "\"*Debug\",\"*Test\",\"excluded\",\"exc_pattern*\""
+                 "],"
+                 "\"record_mode\":\"record-until-full\""
+               "}",
+               tc.ToString().c_str());
+
+  tc = TraceConfig("DELAY(test.Delay1;16)", "");
+  tc2 = TraceConfig("DELAY(test.Delay2;32)", "");
+  tc.Merge(tc2);
+  EXPECT_EQ(2u, tc.GetSyntheticDelayValues().size());
+  EXPECT_STREQ("test.Delay1;16", tc.GetSyntheticDelayValues()[0].c_str());
+  EXPECT_STREQ("test.Delay2;32", tc.GetSyntheticDelayValues()[1].c_str());
+}
+
+TEST(TraceConfigTest, IsCategoryGroupEnabled) {
+  // Enabling a disabled- category does not require all categories to be traced
+  // to be included.
+  TraceConfig tc("disabled-by-default-cc,-excluded", "");
+  EXPECT_STREQ("disabled-by-default-cc,-excluded",
+               tc.ToCategoryFilterString().c_str());
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("some_other_group"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded"));
+
+  // Enabled a disabled- category and also including makes all categories to
+  // be traced require including.
+  tc = TraceConfig("disabled-by-default-cc,included", "");
+  EXPECT_STREQ("included,disabled-by-default-cc",
+               tc.ToCategoryFilterString().c_str());
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("other_included"));
+
+  // Excluding categories won't enable disabled-by-default ones with the
+  // excluded category is also present in the group.
+  tc = TraceConfig("-excluded", "");
+  EXPECT_STREQ("-excluded", tc.ToCategoryFilterString().c_str());
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,disabled-by-default-cc"));
+}
+
+TEST(TraceConfigTest, IsEmptyOrContainsLeadingOrTrailingWhitespace) {
+  // Test that IsEmptyOrContainsLeadingOrTrailingWhitespace actually catches
+  // categories that are explicitly forbidden.
+  // This method is called in a DCHECK to assert that we don't have these types
+  // of strings as categories.
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      " bad_category "));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      " bad_category"));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "bad_category "));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "   bad_category"));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "bad_category   "));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "   bad_category   "));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      ""));
+  EXPECT_FALSE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "good_category"));
+}
+
+TEST(TraceConfigTest, SetTraceOptionValues) {
+  TraceConfig tc;
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+
+  tc.SetTraceRecordMode(RECORD_AS_MUCH_AS_POSSIBLE);
+  EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, tc.GetTraceRecordMode());
+
+  tc.EnableSampling();
+  EXPECT_TRUE(tc.IsSamplingEnabled());
+
+  tc.EnableSystrace();
+  EXPECT_TRUE(tc.IsSystraceEnabled());
+}
+
+TEST(TraceConfigTest, TraceConfigFromMemoryConfigString) {
+  std::string tc_str =
+      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(200, 2000);
+  TraceConfig tc(tc_str);
+  EXPECT_EQ(tc_str, tc.ToString());
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
+  EXPECT_EQ(2u, tc.memory_dump_config_.size());
+
+  EXPECT_EQ(200u, tc.memory_dump_config_[0].periodic_interval_ms);
+  EXPECT_EQ(MemoryDumpLevelOfDetail::LIGHT,
+            tc.memory_dump_config_[0].level_of_detail);
+
+  EXPECT_EQ(2000u, tc.memory_dump_config_[1].periodic_interval_ms);
+  EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED,
+            tc.memory_dump_config_[1].level_of_detail);
+}
+
+TEST(TraceConfigTest, EmptyMemoryDumpConfigTest) {
+  // Empty trigger list should also be specified when converting back to string.
+  TraceConfig tc(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
+  EXPECT_EQ(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers(),
+            tc.ToString());
+  EXPECT_EQ(0u, tc.memory_dump_config_.size());
+}
+
+TEST(TraceConfigTest, LegacyStringToMemoryDumpConfig) {
+  TraceConfig tc(MemoryDumpManager::kTraceCategory, "");
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
+  EXPECT_NE(std::string::npos, tc.ToString().find("memory_dump_config"));
+  EXPECT_EQ(2u, tc.memory_dump_config_.size());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
index 9a072e4..8656c6e 100644
--- a/base/trace_event/trace_event.gypi
+++ b/base/trace_event/trace_event.gypi
@@ -4,13 +4,31 @@
 {
   'variables': {
     'trace_event_sources' : [
+      'trace_event/common/trace_event_common.h',
+      'trace_event/heap_profiler_allocation_context.cc',
+      'trace_event/heap_profiler_allocation_context.h',
+      'trace_event/heap_profiler_allocation_context_tracker.cc',
+      'trace_event/heap_profiler_allocation_context_tracker.h',
+      'trace_event/heap_profiler_allocation_register.cc',
+      'trace_event/heap_profiler_allocation_register_posix.cc',
+      'trace_event/heap_profiler_allocation_register_win.cc',
+      'trace_event/heap_profiler_allocation_register.h',
+      'trace_event/heap_profiler_heap_dump_writer.cc',
+      'trace_event/heap_profiler_heap_dump_writer.h',
+      'trace_event/heap_profiler_stack_frame_deduplicator.cc',
+      'trace_event/heap_profiler_stack_frame_deduplicator.h',
+      'trace_event/heap_profiler_type_name_deduplicator.cc',
+      'trace_event/heap_profiler_type_name_deduplicator.h',
       'trace_event/java_heap_dump_provider_android.cc',
       'trace_event/java_heap_dump_provider_android.h',
       'trace_event/memory_allocator_dump.cc',
       'trace_event/memory_allocator_dump.h',
+      'trace_event/memory_allocator_dump_guid.cc',
+      'trace_event/memory_allocator_dump_guid.h',
       'trace_event/memory_dump_manager.cc',
       'trace_event/memory_dump_manager.h',
       'trace_event/memory_dump_provider.h',
+      'trace_event/memory_dump_request_args.cc',
       'trace_event/memory_dump_request_args.h',
       'trace_event/memory_dump_session_state.cc',
       'trace_event/memory_dump_session_state.h',
@@ -18,12 +36,15 @@
       '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_buffer.cc',
+      'trace_event/trace_buffer.h',
+      'trace_event/trace_config.cc',
+      'trace_event/trace_config.h',
       'trace_event/trace_event.h',
       'trace_event/trace_event_android.cc',
       'trace_event/trace_event_argument.cc',
@@ -32,39 +53,59 @@
       'trace_event/trace_event_etw_export_win.h',
       'trace_event/trace_event_impl.cc',
       'trace_event/trace_event_impl.h',
-      'trace_event/trace_event_impl_constants.cc',
-      'trace_event/trace_event_memory.cc',
-      'trace_event/trace_event_memory.h',
+      'trace_event/trace_event_memory_overhead.cc',
+      'trace_event/trace_event_memory_overhead.h',
       'trace_event/trace_event_synthetic_delay.cc',
       'trace_event/trace_event_synthetic_delay.h',
       'trace_event/trace_event_system_stats_monitor.cc',
       'trace_event/trace_event_system_stats_monitor.h',
-      'trace_event/trace_event_win.cc',
-      'trace_event/trace_event_win.h',
+      'trace_event/trace_log.cc',
+      'trace_event/trace_log.h',
+      'trace_event/trace_log_constants.cc',
+      'trace_event/trace_sampling_thread.cc',
+      'trace_event/trace_sampling_thread.h',
       'trace_event/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/heap_profiler_allocation_context_tracker_unittest.cc',
+      'trace_event/heap_profiler_allocation_register_unittest.cc',
+      'trace_event/heap_profiler_heap_dump_writer_unittest.cc',
+      'trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc',
+      'trace_event/heap_profiler_type_name_deduplicator_unittest.cc',
       'trace_event/java_heap_dump_provider_android_unittest.cc',
       'trace_event/memory_allocator_dump_unittest.cc',
       'trace_event/memory_dump_manager_unittest.cc',
-      'trace_event/process_memory_maps_dump_provider_unittest.cc',
+      'trace_event/process_memory_dump_unittest.cc',
       'trace_event/process_memory_totals_dump_provider_unittest.cc',
+      'trace_event/trace_config_memory_test_util.h',
+      'trace_event/trace_config_unittest.cc',
       'trace_event/trace_event_argument_unittest.cc',
-      'trace_event/trace_event_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',
     ],
+    'conditions': [
+      ['OS == "linux" or OS=="android" or OS=="mac"', {
+        'trace_event_sources': [
+          'trace_event/malloc_dump_provider.cc',
+          'trace_event/malloc_dump_provider.h',
+        ],
+      }],
+      ['OS == "linux" or OS == "android"', {
+          'trace_event_sources': [
+            'trace_event/process_memory_maps_dump_provider.cc',
+          ],
+          'trace_event_test_sources' : [
+            'trace_event/process_memory_maps_dump_provider_unittest.cc',
+          ],
+      }],
+      ['OS == "android"', {
+        'trace_event_test_sources' : [
+          'trace_event/trace_event_android_unittest.cc',
+        ],
+      }],
+    ],
   },
 }
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 2c30b33..7a2a656 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -2,200 +2,20 @@
 // 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_
 
+// This header file defines implementation details of how the trace macros in
+// trace_event_common.h collect and store trace events. Anything not
+// implementation-specific should go in trace_macros_common.h instead of here.
+
 #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/common/trace_event_common.h"
 #include "base/trace_event/trace_event_system_stats_monitor.h"
+#include "base/trace_event/trace_log.h"
 #include "build/build_config.h"
 
 // By default, const char* argument values are assumed to have long-lived scope
@@ -203,10 +23,6 @@
 #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) \
@@ -217,105 +33,6 @@
 #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
@@ -342,540 +59,8 @@
     trace_event_internal::TraceEventSamplingStateScope<bucket_number>   \
         traceEventSamplingScope(category "\0" name);
 
-// Syntactic sugars for the sampling tracing in the main thread.
-#define TRACE_EVENT_SCOPED_SAMPLING_STATE(category, name) \
-    TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(0, category, name)
-#define TRACE_EVENT_GET_SAMPLING_STATE() \
-    TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(0)
-#define TRACE_EVENT_SET_SAMPLING_STATE(category, name) \
-    TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(0, category, name)
-
-
-// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
-// associated arguments. If the category is not enabled, then this
-// does nothing.
-// - category and name strings must have application lifetime (statics or
-//   literals). They may not include " chars.
-#define TRACE_EVENT_BEGIN0(category_group, name) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
-        category_group, name, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_BEGIN1(category_group, name, arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
-        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-#define TRACE_EVENT_BEGIN2(category_group, name, arg1_name, arg1_val, \
-        arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
-        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
-        arg2_name, arg2_val)
-#define TRACE_EVENT_COPY_BEGIN0(category_group, name) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
-        category_group, name, TRACE_EVENT_FLAG_COPY)
-#define TRACE_EVENT_COPY_BEGIN1(category_group, name, arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
-        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
-#define TRACE_EVENT_COPY_BEGIN2(category_group, name, arg1_name, arg1_val, \
-        arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
-        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
-        arg2_name, arg2_val)
-
-// Similar to TRACE_EVENT_BEGINx but with a custom |at| timestamp provided.
-// - |id| is used to match the _BEGIN event with the _END event.
-//   Events are considered to match if their category_group, name and id values
-//   all match. |id| must either be a pointer or an integer value up to 64 bits.
-//   If it's a pointer, the bits will be xored with a hash of the process ID so
-//   that the same pointer on two different processes will not collide.
-#define TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category_group, \
-        name, id, thread_id, timestamp) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
-        timestamp, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0( \
-        category_group, name, id, thread_id, timestamp) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
-        timestamp, TRACE_EVENT_FLAG_COPY)
-#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1( \
-        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
-        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
-#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2( \
-        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
-        arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
-        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \
-        arg2_val)
-
-// Records a single END event for "name" immediately. If the category
-// is not enabled, then this does nothing.
-// - category and name strings must have application lifetime (statics or
-//   literals). They may not include " chars.
-#define TRACE_EVENT_END0(category_group, name) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
-        category_group, name, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_END1(category_group, name, arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
-        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-#define TRACE_EVENT_END2(category_group, name, arg1_name, arg1_val, \
-        arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
-        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
-        arg2_name, arg2_val)
-#define TRACE_EVENT_COPY_END0(category_group, name) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
-        category_group, name, TRACE_EVENT_FLAG_COPY)
-#define TRACE_EVENT_COPY_END1(category_group, name, arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
-        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
-#define TRACE_EVENT_COPY_END2(category_group, name, arg1_name, arg1_val, \
-        arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
-        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
-        arg2_name, arg2_val)
-
-// Similar to TRACE_EVENT_ENDx but with a custom |at| timestamp provided.
-// - |id| is used to match the _BEGIN event with the _END event.
-//   Events are considered to match if their category_group, name and id values
-//   all match. |id| must either be a pointer or an integer value up to 64 bits.
-//   If it's a pointer, the bits will be xored with a hash of the process ID so
-//   that the same pointer on two different processes will not collide.
-#define TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(category_group, \
-        name, id, thread_id, timestamp) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
-        timestamp, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0( \
-        category_group, name, id, thread_id, timestamp) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
-        timestamp, TRACE_EVENT_FLAG_COPY)
-#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1( \
-        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
-        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
-#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2( \
-        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
-        arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
-        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \
-        arg2_val)
-
-// Records the value of a counter called "name" immediately. Value
-// must be representable as a 32 bit integer.
-// - category and name strings must have application lifetime (statics or
-//   literals). They may not include " chars.
-#define TRACE_COUNTER1(category_group, name, value) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
-        category_group, name, TRACE_EVENT_FLAG_NONE, \
-        "value", static_cast<int>(value))
-#define TRACE_COPY_COUNTER1(category_group, name, value) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
-        category_group, name, TRACE_EVENT_FLAG_COPY, \
-        "value", static_cast<int>(value))
-
-// Records the values of a multi-parted counter called "name" immediately.
-// The UI will treat value1 and value2 as parts of a whole, displaying their
-// values as a stacked-bar chart.
-// - category and name strings must have application lifetime (statics or
-//   literals). They may not include " chars.
-#define TRACE_COUNTER2(category_group, name, value1_name, value1_val, \
-        value2_name, value2_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
-        category_group, name, TRACE_EVENT_FLAG_NONE, \
-        value1_name, static_cast<int>(value1_val), \
-        value2_name, static_cast<int>(value2_val))
-#define TRACE_COPY_COUNTER2(category_group, name, value1_name, value1_val, \
-        value2_name, value2_val) \
-    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
-        category_group, name, TRACE_EVENT_FLAG_COPY, \
-        value1_name, static_cast<int>(value1_val), \
-        value2_name, static_cast<int>(value2_val))
-
-// Records the value of a counter called "name" immediately. Value
-// must be representable as a 32 bit integer.
-// - category and name strings must have application lifetime (statics or
-//   literals). They may not include " chars.
-// - |id| is used to disambiguate counters with the same name. It must either
-//   be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
-//   will be xored with a hash of the process ID so that the same pointer on
-//   two different processes will not collide.
-#define TRACE_COUNTER_ID1(category_group, name, id, value) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
-        "value", static_cast<int>(value))
-#define TRACE_COPY_COUNTER_ID1(category_group, name, id, value) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
-        "value", static_cast<int>(value))
-
-// Records the values of a multi-parted counter called "name" immediately.
-// The UI will treat value1 and value2 as parts of a whole, displaying their
-// values as a stacked-bar chart.
-// - category and name strings must have application lifetime (statics or
-//   literals). They may not include " chars.
-// - |id| is used to disambiguate counters with the same name. It must either
-//   be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
-//   will be xored with a hash of the process ID so that the same pointer on
-//   two different processes will not collide.
-#define TRACE_COUNTER_ID2(category_group, name, id, value1_name, value1_val, \
-        value2_name, value2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
-        value1_name, static_cast<int>(value1_val), \
-        value2_name, static_cast<int>(value2_val))
-#define TRACE_COPY_COUNTER_ID2(category_group, name, id, value1_name, \
-        value1_val, value2_name, value2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
-        value1_name, static_cast<int>(value1_val), \
-        value2_name, static_cast<int>(value2_val))
-
-// TRACE_EVENT_SAMPLE_* events are injected by the sampling profiler.
-#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP0(category_group, name,       \
-                                                   thread_id, timestamp)       \
-  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
-      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
-      TRACE_EVENT_FLAG_NONE)
-
-#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1(                            \
-    category_group, name, thread_id, timestamp, arg1_name, arg1_val)           \
-  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
-      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
-      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-
-#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP2(category_group, name,       \
-                                                   thread_id, timestamp,       \
-                                                   arg1_name, arg1_val,        \
-                                                   arg2_name, arg2_val)        \
-  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
-      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
-      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
-
-// ASYNC_STEP_* APIs should be only used by legacy code. New code should
-// consider using NESTABLE_ASYNC_* APIs to describe substeps within an async
-// event.
-// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2
-// associated arguments. If the category is not enabled, then this
-// does nothing.
-// - category and name strings must have application lifetime (statics or
-//   literals). They may not include " chars.
-// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC
-//   events are considered to match if their category_group, name and id values
-//   all match. |id| must either be a pointer or an integer value up to 64 bits.
-//   If it's a pointer, the bits will be xored with a hash of the process ID so
-//   that the same pointer on two different processes will not collide.
-//
-// An asynchronous operation can consist of multiple phases. The first phase is
-// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the
-// ASYNC_STEP_INTO or ASYNC_STEP_PAST macros. The ASYNC_STEP_INTO macro will
-// annotate the block following the call. The ASYNC_STEP_PAST macro will
-// annotate the block prior to the call. Note that any particular event must use
-// only STEP_INTO or STEP_PAST macros; they can not mix and match. When the
-// operation completes, call ASYNC_END.
-//
-// An ASYNC trace typically occurs on a single thread (if not, they will only be
-// drawn on the thread defined in the ASYNC_BEGIN event), but all events in that
-// operation must use the same |name| and |id|. Each step can have its own
-// args.
-#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
-        arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-#define TRACE_EVENT_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
-        arg1_val, arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
-        arg1_name, arg1_val, arg2_name, arg2_val)
-#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category_group, name, id) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY)
-#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
-        arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
-        arg1_name, arg1_val)
-#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
-        arg1_val, arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
-        arg1_name, arg1_val, arg2_name, arg2_val)
-
-// Similar to TRACE_EVENT_ASYNC_BEGINx but with a custom |at| timestamp
-// provided.
-#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
-        name, id, timestamp) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
-        static_cast<int>(base::PlatformThread::CurrentId()), \
-        timestamp, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
-        name, id, timestamp) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
-        static_cast<int>(base::PlatformThread::CurrentId()), \
-        timestamp, TRACE_EVENT_FLAG_COPY)
-
-// Records a single ASYNC_STEP_INTO event for |step| immediately. If the
-// category is not enabled, then this does nothing. The |name| and |id| must
-// match the ASYNC_BEGIN event above. The |step| param identifies this step
-// within the async event. This should be called at the beginning of the next
-// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
-// ASYNC_STEP_PAST events.
-#define TRACE_EVENT_ASYNC_STEP_INTO0(category_group, name, id, step) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
-#define TRACE_EVENT_ASYNC_STEP_INTO1(category_group, name, id, step, \
-                                     arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
-        arg1_name, arg1_val)
-
-// Similar to TRACE_EVENT_ASYNC_STEP_INTOx but with a custom |at| timestamp
-// provided.
-#define TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category_group, name, \
-        id, step, timestamp) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id, \
-        static_cast<int>(base::PlatformThread::CurrentId()), \
-        timestamp, TRACE_EVENT_FLAG_NONE, "step", step)
-
-// Records a single ASYNC_STEP_PAST event for |step| immediately. If the
-// category is not enabled, then this does nothing. The |name| and |id| must
-// match the ASYNC_BEGIN event above. The |step| param identifies this step
-// within the async event. This should be called at the beginning of the next
-// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
-// ASYNC_STEP_INTO events.
-#define TRACE_EVENT_ASYNC_STEP_PAST0(category_group, name, id, step) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
-#define TRACE_EVENT_ASYNC_STEP_PAST1(category_group, name, id, step, \
-                                     arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
-        arg1_name, arg1_val)
-
-// Records a single ASYNC_END event for "name" immediately. If the category
-// is not enabled, then this does nothing.
-#define TRACE_EVENT_ASYNC_END0(category_group, name, id) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-#define TRACE_EVENT_ASYNC_END2(category_group, name, id, arg1_name, arg1_val, \
-        arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
-        arg1_name, arg1_val, arg2_name, arg2_val)
-#define TRACE_EVENT_COPY_ASYNC_END0(category_group, name, id) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY)
-#define TRACE_EVENT_COPY_ASYNC_END1(category_group, name, id, arg1_name, \
-        arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
-        arg1_name, arg1_val)
-#define TRACE_EVENT_COPY_ASYNC_END2(category_group, name, id, arg1_name, \
-        arg1_val, arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
-        arg1_name, arg1_val, arg2_name, arg2_val)
-
-// Similar to TRACE_EVENT_ASYNC_ENDx but with a custom |at| timestamp provided.
-#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(category_group, \
-        name, id, timestamp) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
-        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
-        static_cast<int>(base::PlatformThread::CurrentId()), \
-        timestamp, TRACE_EVENT_FLAG_NONE)
-
-// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
-// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
-// events.
-// - category and name strings must have application lifetime (statics or
-//   literals). They may not include " chars.
-// - A pair of NESTABLE_ASYNC_BEGIN event and NESTABLE_ASYNC_END event is
-//   considered as a match if their category_group, name and id all match.
-// - |id| must either be a pointer or an integer value up to 64 bits.
-//   If it's a pointer, the bits will be xored with a hash of the process ID so
-//   that the same pointer on two different processes will not collide.
-// - |id| is used to match a child NESTABLE_ASYNC event with its parent
-//   NESTABLE_ASYNC event. Therefore, events in the same nested event tree must
-//   be logged using the same id and category_group.
-//
-// Unmatched NESTABLE_ASYNC_END event will be parsed as an event that starts
-// at the first NESTABLE_ASYNC event of that id, and unmatched
-// NESTABLE_ASYNC_BEGIN event will be parsed as an event that ends at the last
-// NESTABLE_ASYNC event of that id. Corresponding warning messages for
-// unmatched events will be shown in the analysis view.
-
-// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with
-// 0, 1 or 2 associated arguments. If the category is not enabled, then this
-// does nothing.
-#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_group, name, id) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
-        arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
-        arg1_val, arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
-        arg2_name, arg2_val)
-// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 0,
-// 1, or 2 associated arguments. If the category is not enabled, then this does
-// nothing.
-#define TRACE_EVENT_NESTABLE_ASYNC_END0(category_group, name, id) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_NESTABLE_ASYNC_END1(category_group, name, id, arg1_name, \
-        arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
-#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
-        arg1_val, arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
-        arg2_name, arg2_val)
-
-#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(category_group, name, \
-        id, arg1_name, arg1_val, arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
-        category_group, name, id, \
-        TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
-        arg1_name, arg1_val, arg2_name, arg2_val)
-#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(category_group, name, \
-        id, arg1_name, arg1_val, arg2_name, arg2_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
-        category_group, name, id, \
-        TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
-        arg1_name, arg1_val, arg2_name, arg2_val)
-
-// 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 TRACE_EVENT_API_CURRENT_THREAD_ID \
+  static_cast<int>(base::PlatformThread::CurrentId())
 
 #define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
   UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) &           \
@@ -883,33 +68,6 @@
             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.
 
@@ -942,24 +100,67 @@
 //                    const char** arg_names,
 //                    const unsigned char* arg_types,
 //                    const unsigned long long* arg_values,
-//                    unsigned char flags)
+//                    const scoped_refptr<ConvertableToTraceFormat>*
+//                    convertable_values,
+//                    unsigned int flags)
 #define TRACE_EVENT_API_ADD_TRACE_EVENT \
     base::trace_event::TraceLog::GetInstance()->AddTraceEvent
 
 // Add a trace event to the platform tracing system.
 // base::trace_event::TraceEventHandle
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_CONTEXT_ID(
+//                    char phase,
+//                    const unsigned char* category_group_enabled,
+//                    const char* name,
+//                    unsigned long long id,
+//                    unsigned long long context_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 int flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_CONTEXT_ID \
+    base::trace_event::TraceLog::GetInstance()->AddTraceEventWithContextId
+
+// Add a trace event to the platform tracing system overriding the pid.
+// The resulting event will have tid = pid == (process_id passed here).
+// base::trace_event::TraceEventHandle
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
+//                    char phase,
+//                    const unsigned char* category_group_enabled,
+//                    const char* name,
+//                    unsigned long long id,
+//                    unsigned long long context_id,
+//                    int process_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 int flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID \
+  base::trace_event::TraceLog::GetInstance()->AddTraceEventWithProcessId
+
+// Add a trace event to the platform tracing system.
+// base::trace_event::TraceEventHandle
 // TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP(
 //                    char phase,
 //                    const unsigned char* category_group_enabled,
 //                    const char* name,
 //                    unsigned long long id,
+//                    unsigned long long context_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)
+//                    const scoped_refptr<ConvertableToTraceFormat>*
+//                    convertable_values,
+//                    unsigned int flags)
 #define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP \
     base::trace_event::TraceLog::GetInstance() \
       ->AddTraceEventWithThreadIdAndTimestamp
@@ -972,6 +173,15 @@
 #define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
     base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDuration
 
+// Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
+// on the convertable value will be called at flush time.
+// TRACE_EVENT_API_ADD_METADATA_EVENT(
+//   const char* event_name,
+//   const char* arg_name,
+//   scoped_refptr<ConvertableToTraceFormat> arg_value)
+#define TRACE_EVENT_API_ADD_METADATA_EVENT \
+    trace_event_internal::AddMetadataEvent
+
 // Defines atomic operations used internally by the tracing system.
 #define TRACE_EVENT_API_ATOMIC_WORD base::subtle::AtomicWord
 #define TRACE_EVENT_API_ATOMIC_LOAD(var) base::subtle::NoBarrier_Load(&(var))
@@ -1032,7 +242,8 @@
       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__); \
+            trace_event_internal::kNoId, flags, \
+            trace_event_internal::kNoId, ##__VA_ARGS__); \
       } \
     } while (0)
 
@@ -1047,12 +258,30 @@
           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__); \
+              trace_event_internal::kNoId, TRACE_EVENT_FLAG_NONE, \
+              trace_event_internal::kNoId, ##__VA_ARGS__); \
       INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
           INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
     }
 
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW( \
+    category_group, name, bind_id, flow_flags, ...) \
+  INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+  trace_event_internal::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
+  if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+    unsigned int trace_event_flags = flow_flags; \
+    trace_event_internal::TraceID trace_event_bind_id(bind_id, \
+                                                      &trace_event_flags); \
+    base::trace_event::TraceEventHandle h = \
+        trace_event_internal::AddTraceEvent( \
+            TRACE_EVENT_PHASE_COMPLETE, \
+            INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+            trace_event_internal::kNoId, trace_event_flags, \
+            trace_event_bind_id.data(), ##__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, \
@@ -1060,102 +289,59 @@
     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; \
+        unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
         trace_event_internal::TraceID trace_event_trace_id( \
             id, &trace_event_flags); \
         trace_event_internal::AddTraceEvent( \
             phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
             name, trace_event_trace_id.data(), trace_event_flags, \
-            ##__VA_ARGS__); \
+            trace_event_internal::kNoId, ##__VA_ARGS__); \
       } \
     } while (0)
 
 // Implementation detail: internal macro to create static category and add
 // event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(phase, category_group, name, \
+                                                timestamp, flags, ...)       \
+  do {                                                                       \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                  \
+    if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {  \
+      trace_event_internal::AddTraceEventWithThreadIdAndTimestamp(           \
+          phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,     \
+          trace_event_internal::kNoId, trace_event_internal::kNoId,          \
+          TRACE_EVENT_API_CURRENT_THREAD_ID,                                 \
+          base::TimeTicks::FromInternalValue(timestamp),                     \
+          flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP,                       \
+          trace_event_internal::kNoId, ##__VA_ARGS__);                       \
+    }                                                                        \
+  } while (0)
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
 #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(phase, \
         category_group, name, id, thread_id, timestamp, flags, ...) \
     do { \
       INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
       if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
-        unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+        unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
         trace_event_internal::TraceID trace_event_trace_id( \
             id, &trace_event_flags); \
         trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
             phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
-            name, trace_event_trace_id.data(), \
+            name, trace_event_trace_id.data(), trace_event_internal::kNoId, \
             thread_id, base::TimeTicks::FromInternalValue(timestamp), \
             trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
-            ##__VA_ARGS__); \
+            trace_event_internal::kNoId, ##__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;
+const unsigned long long kNoId = 0;
 
 // TraceID encapsulates an ID that can either be an integer or pointer. Pointers
 // are by default mangled with the Process ID so that they are unlikely to
@@ -1208,35 +394,35 @@
    private:
     unsigned long long data_;
   };
-  TraceID(const void* id, unsigned char* flags)
+  TraceID(const void* id, unsigned int* 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()) {
+  TraceID(ForceMangle id, unsigned int* flags) : data_(id.data()) {
     *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
   }
-  TraceID(DontMangle id, unsigned char* flags) : data_(id.data()) {
+  TraceID(DontMangle id, unsigned int* flags) : data_(id.data()) {
   }
-  TraceID(unsigned long long id, unsigned char* flags)
+  TraceID(unsigned long long id, unsigned int* flags)
       : data_(id) { (void)flags; }
-  TraceID(unsigned long id, unsigned char* flags)
+  TraceID(unsigned long id, unsigned int* flags)
       : data_(id) { (void)flags; }
-  TraceID(unsigned int id, unsigned char* flags)
+  TraceID(unsigned int id, unsigned int* flags)
       : data_(id) { (void)flags; }
-  TraceID(unsigned short id, unsigned char* flags)
+  TraceID(unsigned short id, unsigned int* flags)
       : data_(id) { (void)flags; }
-  TraceID(unsigned char id, unsigned char* flags)
+  TraceID(unsigned char id, unsigned int* flags)
       : data_(id) { (void)flags; }
-  TraceID(long long id, unsigned char* flags)
+  TraceID(long long id, unsigned int* flags)
       : data_(static_cast<unsigned long long>(id)) { (void)flags; }
-  TraceID(long id, unsigned char* flags)
+  TraceID(long id, unsigned int* flags)
       : data_(static_cast<unsigned long long>(id)) { (void)flags; }
-  TraceID(int id, unsigned char* flags)
+  TraceID(int id, unsigned int* flags)
       : data_(static_cast<unsigned long long>(id)) { (void)flags; }
-  TraceID(short id, unsigned char* flags)
+  TraceID(short id, unsigned int* flags)
       : data_(static_cast<unsigned long long>(id)) { (void)flags; }
-  TraceID(signed char id, unsigned char* flags)
+  TraceID(signed char id, unsigned int* flags)
       : data_(static_cast<unsigned long long>(id)) { (void)flags; }
 
   unsigned long long data() const { return data_; }
@@ -1324,8 +510,8 @@
   *value = type_value.as_uint;
 }
 
-// base::Time and base::TimeTicks version of SetTraceValue to make it easier to
-// trace these types.
+// base::Time, base::TimeTicks, etc. versions of SetTraceValue to make it easier
+// to trace these types.
 static inline void SetTraceValue(const base::Time arg,
                                  unsigned char* type,
                                  unsigned long long* value) {
@@ -1340,6 +526,13 @@
   *value = arg.ToInternalValue();
 }
 
+static inline void SetTraceValue(const base::ThreadTicks arg,
+                                 unsigned char* type,
+                                 unsigned long long* value) {
+  *type = TRACE_VALUE_TYPE_INT;
+  *value = arg.ToInternalValue();
+}
+
 // These AddTraceEvent and AddTraceEventWithThreadIdAndTimestamp template
 // functions are defined here instead of in the macro, because the arg_values
 // could be temporary objects, such as std::string. In order to store
@@ -1352,17 +545,19 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
+    unsigned long long context_id,
     int thread_id,
     const base::TimeTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
+    unsigned long long bind_id,
     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);
+      phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
+      timestamp, num_args, &arg1_name, arg_types, NULL, &arg1_val, flags);
 }
 
 template<class ARG1_TYPE>
@@ -1372,9 +567,11 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
+    unsigned long long context_id,
     int thread_id,
     const base::TimeTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
+    unsigned long long bind_id,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val,
     const char* arg2_name,
@@ -1393,8 +590,9 @@
   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);
+      phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
+      timestamp, num_args, arg_names, arg_types, arg_values,
+      convertable_values, flags);
 }
 
 template<class ARG2_TYPE>
@@ -1404,9 +602,11 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
+    unsigned long long context_id,
     int thread_id,
     const base::TimeTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
+    unsigned long long bind_id,
     const char* arg1_name,
     const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
     const char* arg2_name,
@@ -1425,8 +625,9 @@
   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);
+      phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
+      timestamp, num_args, arg_names, arg_types, arg_values,
+      convertable_values, flags);
 }
 
 static inline base::trace_event::TraceEventHandle
@@ -1435,9 +636,11 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
+    unsigned long long context_id,
     int thread_id,
     const base::TimeTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
+    unsigned long long bind_id,
     const char* arg1_name,
     const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
     const char* arg2_name,
@@ -1451,8 +654,9 @@
       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);
+      phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
+      timestamp, num_args, arg_names, arg_types, NULL, convertable_values,
+      flags);
 }
 
 static inline base::trace_event::TraceEventHandle
@@ -1461,12 +665,14 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
+    unsigned long long context_id,
     int thread_id,
     const base::TimeTicks& timestamp,
-    unsigned char flags) {
+    unsigned int flags,
+    unsigned long long bind_id) {
   return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
-      phase, category_group_enabled, name, id, thread_id, timestamp,
-      kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
+      phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
+      timestamp, kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
 }
 
 static inline base::trace_event::TraceEventHandle AddTraceEvent(
@@ -1474,11 +680,13 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
-    unsigned char flags) {
+    unsigned int flags,
+    unsigned long long bind_id) {
   const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  const base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+  const base::TimeTicks now = base::TimeTicks::Now();
   return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
-                                               name, id, thread_id, now, flags);
+                                               name, id, kNoId, thread_id, now,
+                                               flags, bind_id);
 }
 
 template<class ARG1_TYPE>
@@ -1488,9 +696,11 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
+    unsigned long long context_id,
     int thread_id,
     const base::TimeTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
+    unsigned long long bind_id,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val) {
   const int num_args = 1;
@@ -1498,8 +708,8 @@
   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);
+      phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
+      timestamp, num_args, &arg1_name, arg_types, arg_values, NULL, flags);
 }
 
 template<class ARG1_TYPE>
@@ -1508,13 +718,15 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
-    unsigned char flags,
+    unsigned int flags,
+    unsigned long long bind_id,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+  base::TimeTicks now = base::TimeTicks::Now();
   return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
-                                               name, id, thread_id, now, flags,
+                                               name, id, kNoId, thread_id, now,
+                                               flags, bind_id,
                                                arg1_name, arg1_val);
 }
 
@@ -1525,9 +737,11 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
+    unsigned long long context_id,
     int thread_id,
     const base::TimeTicks& timestamp,
-    unsigned char flags,
+    unsigned int flags,
+    unsigned long long bind_id,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val,
     const char* arg2_name,
@@ -1539,8 +753,8 @@
   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);
+      phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
+      timestamp, num_args, arg_names, arg_types, arg_values, NULL, flags);
 }
 
 template<class ARG1_TYPE, class ARG2_TYPE>
@@ -1549,19 +763,52 @@
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
-    unsigned char flags,
+    unsigned int flags,
+    unsigned long long bind_id,
     const char* arg1_name,
     const ARG1_TYPE& arg1_val,
     const char* arg2_name,
     const ARG2_TYPE& arg2_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+  base::TimeTicks now = base::TimeTicks::Now();
   return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
-                                               name, id, thread_id, now, flags,
+                                               name, id, kNoId, thread_id, now,
+                                               flags, bind_id,
                                                arg1_name, arg1_val,
                                                arg2_name, arg2_val);
 }
 
+static inline void AddMetadataEvent(
+    const char* event_name,
+    const char* arg_name,
+    scoped_refptr<base::trace_event::ConvertableToTraceFormat> arg_value) {
+  const char* arg_names[1] = {arg_name};
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[1] = {arg_value};
+  unsigned char arg_types[1] = {TRACE_VALUE_TYPE_CONVERTABLE};
+  base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
+      event_name,
+      1,  // num_args
+      arg_names, arg_types,
+      nullptr,  // arg_values
+      convertable_values, TRACE_EVENT_FLAG_NONE);
+}
+
+template <class ARG1_TYPE>
+static void AddMetadataEvent(const char* event_name,
+                             const char* arg_name,
+                             const ARG1_TYPE& arg_val) {
+  const int num_args = 1;
+  const char* arg_names[1] = {arg_name};
+  unsigned char arg_types[1];
+  unsigned long long arg_values[1];
+  SetTraceValue(arg_val, &arg_types[0], &arg_values[0]);
+
+  base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
+      event_name, num_args, arg_names, arg_types, arg_values, nullptr,
+      TRACE_EVENT_FLAG_NONE);
+}
+
 // Used by TRACE_EVENTx macros. Do not use directly.
 class TRACE_EVENT_API_CLASS_EXPORT ScopedTracer {
  public:
diff --git a/base/trace_event/trace_event_android.cc b/base/trace_event/trace_event_android.cc
index 26bd0c7..01ca8e4 100644
--- a/base/trace_event/trace_event_android.cc
+++ b/base/trace_event/trace_event_android.cc
@@ -8,15 +8,34 @@
 
 #include "base/format_macros.h"
 #include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/trace_event/trace_event.h"
 
+namespace base {
+namespace trace_event {
+
 namespace {
 
 int g_atrace_fd = -1;
 const char kATraceMarkerFile[] = "/sys/kernel/debug/tracing/trace_marker";
 
+void WriteToATrace(int fd, const char* buffer, size_t size) {
+  size_t total_written = 0;
+  while (total_written < size) {
+    ssize_t written = HANDLE_EINTR(write(
+        fd, buffer + total_written, size - total_written));
+    if (written <= 0)
+      break;
+    total_written += written;
+  }
+  if (total_written < size) {
+    PLOG(WARNING) << "Failed to write buffer '" << std::string(buffer, size)
+                  << "' to " << kATraceMarkerFile;
+  }
+}
+
 void WriteEvent(
     char phase,
     const char* category_group,
@@ -24,28 +43,26 @@
     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);
+    const TraceEvent::TraceValue* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  std::string out = StringPrintf("%c|%d|%s", phase, getpid(), name);
   if (flags & TRACE_EVENT_FLAG_HAS_ID)
-    base::StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
+    StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
   out += '|';
 
-  for (int i = 0; i < base::trace_event::kTraceMaxNumArgs && arg_names[i];
+  for (int i = 0; i < 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) {
+    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);
-    }
+    else
+      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, "\"", "");
@@ -56,28 +73,25 @@
 
   out += '|';
   out += category_group;
-  write(g_atrace_fd, out.c_str(), out.size());
+  WriteToATrace(g_atrace_fd, out.c_str(), out.size());
 }
 
-void NoOpOutputCallback(base::WaitableEvent* complete_event,
-                        const scoped_refptr<base::RefCountedString>&,
+void NoOpOutputCallback(WaitableEvent* complete_event,
+                        const scoped_refptr<RefCountedString>&,
                         bool has_more_events) {
   if (!has_more_events)
     complete_event->Signal();
 }
 
-void EndChromeTracing(base::trace_event::TraceLog* trace_log,
-                      base::WaitableEvent* complete_event) {
+void EndChromeTracing(TraceLog* trace_log,
+                      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));
+  trace_log->Flush(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
@@ -92,14 +106,14 @@
   if (g_atrace_fd != -1)
     return;
 
-  g_atrace_fd = open(kATraceMarkerFile, O_WRONLY);
+  g_atrace_fd = HANDLE_EINTR(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));
+  TraceConfig trace_config;
+  trace_config.SetTraceRecordMode(RECORD_CONTINUOUSLY);
+  SetEnabled(trace_config, TraceLog::RECORDING_MODE);
 }
 
 void TraceLog::StopATrace() {
@@ -154,7 +168,7 @@
       WriteEvent('B', category_group, name_, id_,
                  arg_names_, arg_types_, arg_values_, convertable_values_,
                  flags_);
-      write(g_atrace_fd, "E", 1);
+      WriteToATrace(g_atrace_fd, "E", 1);
       break;
 
     case TRACE_EVENT_PHASE_COUNTER:
@@ -166,7 +180,7 @@
           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());
+        WriteToATrace(g_atrace_fd, out.c_str(), out.size());
       }
       break;
 
@@ -177,7 +191,7 @@
 }
 
 void TraceLog::AddClockSyncMetadataEvent() {
-  int atrace_fd = open(kATraceMarkerFile, O_WRONLY | O_APPEND);
+  int atrace_fd = HANDLE_EINTR(open(kATraceMarkerFile, O_WRONLY | O_APPEND));
   if (atrace_fd == -1) {
     PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
     return;
@@ -187,12 +201,10 @@
   // 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;
+  double now_in_seconds = (TimeTicks::Now() - TimeTicks()).InSecondsF();
   std::string marker = StringPrintf(
       "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
-  if (write(atrace_fd, marker.c_str(), marker.size()) == -1)
-    PLOG(WARNING) << "Couldn't write to " << kATraceMarkerFile;
+  WriteToATrace(atrace_fd, marker.c_str(), marker.size());
   close(atrace_fd);
 }
 
diff --git a/base/trace_event/trace_event_android_unittest.cc b/base/trace_event/trace_event_android_unittest.cc
new file mode 100644
index 0000000..58bd77e
--- /dev/null
+++ b/base/trace_event/trace_event_android_unittest.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(TraceEventAndroidTest, WriteToATrace) {
+  // Just a smoke test to ensure no crash.
+  TraceLog* trace_log = TraceLog::GetInstance();
+  trace_log->StartATrace();
+  TRACE_EVENT0("test", "test-event");
+  trace_log->StopATrace();
+  trace_log->AddClockSyncMetadataEvent();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc
index 88b1879..72c6866 100644
--- a/base/trace_event/trace_event_argument.cc
+++ b/base/trace_event/trace_event_argument.cc
@@ -4,113 +4,468 @@
 
 #include "base/trace_event/trace_event_argument.h"
 
+#include <utility>
+
+#include "base/bits.h"
 #include "base/json/json_writer.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
 #include "base/values.h"
 
 namespace base {
 namespace trace_event {
 
-TracedValue::TracedValue() : root_(new DictionaryValue()) {
-  stack_.push_back(root_.get());
+namespace {
+const char kTypeStartDict = '{';
+const char kTypeEndDict = '}';
+const char kTypeStartArray = '[';
+const char kTypeEndArray = ']';
+const char kTypeBool = 'b';
+const char kTypeInt = 'i';
+const char kTypeDouble = 'd';
+const char kTypeString = 's';
+const char kTypeCStr = '*';
+
+#ifndef NDEBUG
+const bool kStackTypeDict = false;
+const bool kStackTypeArray = true;
+#define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
+#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
+#define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
+#define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
+#else
+#define DCHECK_CURRENT_CONTAINER_IS(x) do {} while (0)
+#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) do {} while (0)
+#define DEBUG_PUSH_CONTAINER(x) do {} while (0)
+#define DEBUG_POP_CONTAINER() do {} while (0)
+#endif
+
+inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
+  pickle.WriteBytes(&kTypeCStr, 1);
+  pickle.WriteUInt64(static_cast<uint64>(reinterpret_cast<uintptr_t>(ptr)));
+}
+
+inline void WriteKeyNameWithCopy(Pickle& pickle, base::StringPiece str) {
+  pickle.WriteBytes(&kTypeString, 1);
+  pickle.WriteString(str);
+}
+
+std::string ReadKeyName(PickleIterator& pickle_iterator) {
+  const char* type = nullptr;
+  bool res = pickle_iterator.ReadBytes(&type, 1);
+  std::string key_name;
+  if (res && *type == kTypeCStr) {
+    uint64 ptr_value = 0;
+    res = pickle_iterator.ReadUInt64(&ptr_value);
+    key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
+  } else if (res && *type == kTypeString) {
+    res = pickle_iterator.ReadString(&key_name);
+  }
+  DCHECK(res);
+  return key_name;
+}
+}  // namespace
+
+TracedValue::TracedValue() : TracedValue(0) {
+}
+
+TracedValue::TracedValue(size_t capacity) {
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  if (capacity)
+    pickle_.Reserve(capacity);
 }
 
 TracedValue::~TracedValue() {
-  DCHECK_EQ(1u, stack_.size());
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_POP_CONTAINER();
+  DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
 }
 
 void TracedValue::SetInteger(const char* name, int value) {
-  GetCurrentDictionary()->SetInteger(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetIntegerWithCopiedName(base::StringPiece name, int value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+  WriteKeyNameWithCopy(pickle_, name);
 }
 
 void TracedValue::SetDouble(const char* name, double value) {
-  GetCurrentDictionary()->SetDouble(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetDoubleWithCopiedName(base::StringPiece name,
+                                          double value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+  WriteKeyNameWithCopy(pickle_, name);
 }
 
 void TracedValue::SetBoolean(const char* name, bool value) {
-  GetCurrentDictionary()->SetBoolean(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
 }
 
-void TracedValue::SetString(const char* name, const std::string& value) {
-  GetCurrentDictionary()->SetString(name, value);
+void TracedValue::SetBooleanWithCopiedName(base::StringPiece name,
+                                           bool value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+  WriteKeyNameWithCopy(pickle_, name);
 }
 
-void TracedValue::SetValue(const char* name, scoped_ptr<Value> value) {
-  GetCurrentDictionary()->Set(name, value.Pass());
+void TracedValue::SetString(const char* name, base::StringPiece value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetStringWithCopiedName(base::StringPiece name,
+                                          base::StringPiece value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameWithCopy(pickle_, name);
+}
+
+void TracedValue::SetValue(const char* name, const TracedValue& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  BeginDictionary(name);
+  pickle_.WriteBytes(value.pickle_.payload(),
+                     static_cast<int>(value.pickle_.payload_size()));
+  EndDictionary();
+}
+
+void TracedValue::SetValueWithCopiedName(base::StringPiece name,
+                                         const TracedValue& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  BeginDictionaryWithCopiedName(name);
+  pickle_.WriteBytes(value.pickle_.payload(),
+                     static_cast<int>(value.pickle_.payload_size()));
+  EndDictionary();
 }
 
 void TracedValue::BeginDictionary(const char* name) {
-  DictionaryValue* dictionary = new DictionaryValue();
-  GetCurrentDictionary()->Set(name, make_scoped_ptr(dictionary));
-  stack_.push_back(dictionary);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::BeginDictionaryWithCopiedName(base::StringPiece name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+  WriteKeyNameWithCopy(pickle_, name);
 }
 
 void TracedValue::BeginArray(const char* name) {
-  ListValue* array = new ListValue();
-  GetCurrentDictionary()->Set(name, make_scoped_ptr(array));
-  stack_.push_back(array);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::BeginArrayWithCopiedName(base::StringPiece name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+  WriteKeyNameWithCopy(pickle_, name);
 }
 
 void TracedValue::EndDictionary() {
-  DCHECK_GT(stack_.size(), 1u);
-  DCHECK(GetCurrentDictionary());
-  stack_.pop_back();
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_POP_CONTAINER();
+  pickle_.WriteBytes(&kTypeEndDict, 1);
 }
 
 void TracedValue::AppendInteger(int value) {
-  GetCurrentArray()->AppendInteger(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
 }
 
 void TracedValue::AppendDouble(double value) {
-  GetCurrentArray()->AppendDouble(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
 }
 
 void TracedValue::AppendBoolean(bool value) {
-  GetCurrentArray()->AppendBoolean(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
 }
 
-void TracedValue::AppendString(const std::string& value) {
-  GetCurrentArray()->AppendString(value);
+void TracedValue::AppendString(base::StringPiece value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
 }
 
 void TracedValue::BeginArray() {
-  ListValue* array = new ListValue();
-  GetCurrentArray()->Append(array);
-  stack_.push_back(array);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
 }
 
 void TracedValue::BeginDictionary() {
-  DictionaryValue* dictionary = new DictionaryValue();
-  GetCurrentArray()->Append(dictionary);
-  stack_.push_back(dictionary);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
 }
 
 void TracedValue::EndArray() {
-  DCHECK_GT(stack_.size(), 1u);
-  DCHECK(GetCurrentArray());
-  stack_.pop_back();
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_POP_CONTAINER();
+  pickle_.WriteBytes(&kTypeEndArray, 1);
 }
 
-DictionaryValue* TracedValue::GetCurrentDictionary() {
-  DCHECK(!stack_.empty());
-  DictionaryValue* dictionary = NULL;
-  stack_.back()->GetAsDictionary(&dictionary);
-  DCHECK(dictionary);
-  return dictionary;
+void TracedValue::SetValue(const char* name, scoped_ptr<base::Value> value) {
+  SetBaseValueWithCopiedName(name, *value);
 }
 
-ListValue* TracedValue::GetCurrentArray() {
-  DCHECK(!stack_.empty());
-  ListValue* list = NULL;
-  stack_.back()->GetAsList(&list);
-  DCHECK(list);
-  return list;
+void TracedValue::SetBaseValueWithCopiedName(base::StringPiece name,
+                                             const base::Value& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  switch (value.GetType()) {
+    case base::Value::TYPE_NULL:
+    case base::Value::TYPE_BINARY:
+      NOTREACHED();
+      break;
+
+    case base::Value::TYPE_BOOLEAN: {
+      bool bool_value;
+      value.GetAsBoolean(&bool_value);
+      SetBooleanWithCopiedName(name, bool_value);
+    } break;
+
+    case base::Value::TYPE_INTEGER: {
+      int int_value;
+      value.GetAsInteger(&int_value);
+      SetIntegerWithCopiedName(name, int_value);
+    } break;
+
+    case base::Value::TYPE_DOUBLE: {
+      double double_value;
+      value.GetAsDouble(&double_value);
+      SetDoubleWithCopiedName(name, double_value);
+    } break;
+
+    case base::Value::TYPE_STRING: {
+      const StringValue* string_value;
+      value.GetAsString(&string_value);
+      SetStringWithCopiedName(name, string_value->GetString());
+    } break;
+
+    case base::Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dict_value;
+      value.GetAsDictionary(&dict_value);
+      BeginDictionaryWithCopiedName(name);
+      for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
+           it.Advance()) {
+        SetBaseValueWithCopiedName(it.key(), it.value());
+      }
+      EndDictionary();
+    } break;
+
+    case base::Value::TYPE_LIST: {
+      const ListValue* list_value;
+      value.GetAsList(&list_value);
+      BeginArrayWithCopiedName(name);
+      for (base::Value* base_value : *list_value)
+        AppendBaseValue(*base_value);
+      EndArray();
+    } break;
+  }
+}
+
+void TracedValue::AppendBaseValue(const base::Value& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  switch (value.GetType()) {
+    case base::Value::TYPE_NULL:
+    case base::Value::TYPE_BINARY:
+      NOTREACHED();
+      break;
+
+    case base::Value::TYPE_BOOLEAN: {
+      bool bool_value;
+      value.GetAsBoolean(&bool_value);
+      AppendBoolean(bool_value);
+    } break;
+
+    case base::Value::TYPE_INTEGER: {
+      int int_value;
+      value.GetAsInteger(&int_value);
+      AppendInteger(int_value);
+    } break;
+
+    case base::Value::TYPE_DOUBLE: {
+      double double_value;
+      value.GetAsDouble(&double_value);
+      AppendDouble(double_value);
+    } break;
+
+    case base::Value::TYPE_STRING: {
+      const StringValue* string_value;
+      value.GetAsString(&string_value);
+      AppendString(string_value->GetString());
+    } break;
+
+    case base::Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dict_value;
+      value.GetAsDictionary(&dict_value);
+      BeginDictionary();
+      for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
+           it.Advance()) {
+        SetBaseValueWithCopiedName(it.key(), it.value());
+      }
+      EndDictionary();
+    } break;
+
+    case base::Value::TYPE_LIST: {
+      const ListValue* list_value;
+      value.GetAsList(&list_value);
+      BeginArray();
+      for (base::Value* base_value : *list_value)
+        AppendBaseValue(*base_value);
+      EndArray();
+    } break;
+  }
+}
+
+scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
+  scoped_ptr<DictionaryValue> root(new DictionaryValue);
+  DictionaryValue* cur_dict = root.get();
+  ListValue* cur_list = nullptr;
+  std::vector<Value*> stack;
+  PickleIterator it(pickle_);
+  const char* type;
+
+  while (it.ReadBytes(&type, 1)) {
+    DCHECK((cur_dict && !cur_list) || (cur_list && !cur_dict));
+    switch (*type) {
+      case kTypeStartDict: {
+        auto new_dict = new DictionaryValue();
+        if (cur_dict) {
+          cur_dict->SetWithoutPathExpansion(ReadKeyName(it),
+                                            make_scoped_ptr(new_dict));
+          stack.push_back(cur_dict);
+          cur_dict = new_dict;
+        } else {
+          cur_list->Append(make_scoped_ptr(new_dict));
+          stack.push_back(cur_list);
+          cur_list = nullptr;
+          cur_dict = new_dict;
+        }
+      } break;
+
+      case kTypeEndArray:
+      case kTypeEndDict: {
+        if (stack.back()->GetAsDictionary(&cur_dict)) {
+          cur_list = nullptr;
+        } else if (stack.back()->GetAsList(&cur_list)) {
+          cur_dict = nullptr;
+        }
+        stack.pop_back();
+      } break;
+
+      case kTypeStartArray: {
+        auto new_list = new ListValue();
+        if (cur_dict) {
+          cur_dict->SetWithoutPathExpansion(ReadKeyName(it),
+                                            make_scoped_ptr(new_list));
+          stack.push_back(cur_dict);
+          cur_dict = nullptr;
+          cur_list = new_list;
+        } else {
+          cur_list->Append(make_scoped_ptr(new_list));
+          stack.push_back(cur_list);
+          cur_list = new_list;
+        }
+      } break;
+
+      case kTypeBool: {
+        bool value;
+        CHECK(it.ReadBool(&value));
+        if (cur_dict) {
+          cur_dict->SetBooleanWithoutPathExpansion(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendBoolean(value);
+        }
+      } break;
+
+      case kTypeInt: {
+        int value;
+        CHECK(it.ReadInt(&value));
+        if (cur_dict) {
+          cur_dict->SetIntegerWithoutPathExpansion(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendInteger(value);
+        }
+      } break;
+
+      case kTypeDouble: {
+        double value;
+        CHECK(it.ReadDouble(&value));
+        if (cur_dict) {
+          cur_dict->SetDoubleWithoutPathExpansion(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendDouble(value);
+        }
+      } break;
+
+      case kTypeString: {
+        std::string value;
+        CHECK(it.ReadString(&value));
+        if (cur_dict) {
+          cur_dict->SetStringWithoutPathExpansion(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendString(value);
+        }
+      } break;
+
+      default:
+        NOTREACHED();
+    }
+  }
+  DCHECK(stack.empty());
+  return std::move(root);
 }
 
 void TracedValue::AppendAsTraceFormat(std::string* out) const {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
+
+  // TODO(primiano): this could be smarter, skip the ToBaseValue encoding and
+  // produce the JSON on its own. This will require refactoring JSONWriter
+  // to decouple the base::Value traversal from the JSON writing bits
   std::string tmp;
-  JSONWriter::Write(stack_.front(), &tmp);
+  JSONWriter::Write(*ToBaseValue(), &tmp);
   *out += tmp;
-  DCHECK_EQ(1u, stack_.size()) << tmp;
+}
+
+void TracedValue::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  const size_t kPickleHeapAlign = 4096;  // Must be == Pickle::kPickleHeapAlign.
+  overhead->Add("TracedValue",
+
+                /* allocated size */
+                bits::Align(pickle_.GetTotalAllocatedSize(), kPickleHeapAlign),
+
+                /* resident size */
+                bits::Align(pickle_.size(), kPickleHeapAlign));
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/trace_event_argument.h b/base/trace_event/trace_event_argument.h
index d86cfd1..dbdd67f 100644
--- a/base/trace_event/trace_event_argument.h
+++ b/base/trace_event/trace_event_argument.h
@@ -9,11 +9,12 @@
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
-#include "base/trace_event/trace_event.h"
+#include "base/pickle.h"
+#include "base/strings/string_piece.h"
+#include "base/trace_event/trace_event_impl.h"
 
 namespace base {
-class DictionaryValue;
-class ListValue;
+
 class Value;
 
 namespace trace_event {
@@ -21,35 +22,65 @@
 class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
  public:
   TracedValue();
+  explicit TracedValue(size_t capacity);
 
   void EndDictionary();
   void EndArray();
 
+  // These methods assume that |name| is a long lived "quoted" string.
   void SetInteger(const char* name, int value);
-  void SetDouble(const char* name, double);
+  void SetDouble(const char* name, double value);
   void SetBoolean(const char* name, bool value);
-  void SetString(const char* name, const std::string& value);
-  void SetValue(const char* name, scoped_ptr<Value> value);
+  void SetString(const char* name, base::StringPiece value);
+  void SetValue(const char* name, const TracedValue& value);
   void BeginDictionary(const char* name);
   void BeginArray(const char* name);
 
+  // These, instead, can be safely passed a temporary string.
+  void SetIntegerWithCopiedName(base::StringPiece name, int value);
+  void SetDoubleWithCopiedName(base::StringPiece name, double value);
+  void SetBooleanWithCopiedName(base::StringPiece name, bool value);
+  void SetStringWithCopiedName(base::StringPiece name,
+                               base::StringPiece value);
+  void SetValueWithCopiedName(base::StringPiece name,
+                              const TracedValue& value);
+  void BeginDictionaryWithCopiedName(base::StringPiece name);
+  void BeginArrayWithCopiedName(base::StringPiece name);
+
   void AppendInteger(int);
   void AppendDouble(double);
   void AppendBoolean(bool);
-  void AppendString(const std::string&);
+  void AppendString(base::StringPiece);
   void BeginArray();
   void BeginDictionary();
 
+  // ConvertableToTraceFormat implementation.
   void AppendAsTraceFormat(std::string* out) const override;
 
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+  // DEPRECATED: do not use, here only for legacy reasons. These methods causes
+  // a copy-and-translation of the base::Value into the equivalent TracedValue.
+  // TODO(primiano): migrate the (three) existing clients to the cheaper
+  // SetValue(TracedValue) API. crbug.com/495628.
+  void SetValue(const char* name, scoped_ptr<base::Value> value);
+  void SetBaseValueWithCopiedName(base::StringPiece name,
+                                  const base::Value& value);
+  void AppendBaseValue(const base::Value& value);
+
+  // Public for tests only.
+  scoped_ptr<base::Value> ToBaseValue() const;
+
  private:
   ~TracedValue() override;
 
-  DictionaryValue* GetCurrentDictionary();
-  ListValue* GetCurrentArray();
+  Pickle pickle_;
 
-  scoped_ptr<base::Value> root_;
-  std::vector<Value*> stack_;  // Weak references.
+#ifndef NDEBUG
+  // In debug builds checks the pairings of {Start,End}{Dictionary,Array}
+  std::vector<bool> nesting_stack_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(TracedValue);
 };
 
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc
index c59910e..c9ccdb4 100644
--- a/base/trace_event/trace_event_argument_unittest.cc
+++ b/base/trace_event/trace_event_argument_unittest.cc
@@ -3,6 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/trace_event/trace_event_argument.h"
+
+#include <utility>
+
+#include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -14,10 +18,24 @@
   value->SetDouble("double", 0.0);
   value->SetBoolean("bool", true);
   value->SetString("string", "string");
+  std::string json = "PREFIX";
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ(
+      "PREFIX{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}",
+      json);
+}
+
+TEST(TraceEventArgumentTest, NoDotPathExpansion) {
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->SetInteger("in.t", 2014);
+  value->SetDouble("doub.le", 0.0);
+  value->SetBoolean("bo.ol", true);
+  value->SetString("str.ing", "str.ing");
   std::string json;
   value->AppendAsTraceFormat(&json);
-  EXPECT_EQ("{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}",
-            json);
+  EXPECT_EQ(
+      "{\"bo.ol\":true,\"doub.le\":0.0,\"in.t\":2014,\"str.ing\":\"str.ing\"}",
+      json);
 }
 
 TEST(TraceEventArgumentTest, Hierarchy) {
@@ -49,5 +67,96 @@
       json);
 }
 
+TEST(TraceEventArgumentTest, LongStrings) {
+  std::string kLongString = "supercalifragilisticexpialidocious";
+  std::string kLongString2 = "0123456789012345678901234567890123456789";
+  char kLongString3[4096];
+  for (size_t i = 0; i < sizeof(kLongString3); ++i)
+    kLongString3[i] = 'a' + (i % 25);
+  kLongString3[sizeof(kLongString3) - 1] = '\0';
+
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->SetString("a", "short");
+  value->SetString("b", kLongString);
+  value->BeginArray("c");
+  value->AppendString(kLongString2);
+  value->AppendString("");
+  value->BeginDictionary();
+  value->SetString("a", kLongString3);
+  value->EndDictionary();
+  value->EndArray();
+
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"a\":\"short\",\"b\":\"" + kLongString + "\",\"c\":[\"" +
+                kLongString2 + "\",\"\",{\"a\":\"" + kLongString3 + "\"}]}",
+            json);
+}
+
+TEST(TraceEventArgumentTest, PassBaseValue) {
+  FundamentalValue int_value(42);
+  FundamentalValue bool_value(true);
+  FundamentalValue double_value(42.0f);
+
+  auto dict_value = make_scoped_ptr(new DictionaryValue);
+  dict_value->SetBoolean("bool", true);
+  dict_value->SetInteger("int", 42);
+  dict_value->SetDouble("double", 42.0f);
+  dict_value->SetString("string", std::string("a") + "b");
+  dict_value->SetString("string", std::string("a") + "b");
+
+  auto list_value = make_scoped_ptr(new ListValue);
+  list_value->AppendBoolean(false);
+  list_value->AppendInteger(1);
+  list_value->AppendString("in_list");
+  list_value->Append(std::move(dict_value));
+
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->BeginDictionary("outer_dict");
+  value->SetValue("inner_list", std::move(list_value));
+  value->EndDictionary();
+
+  dict_value.reset();
+  list_value.reset();
+
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ(
+      "{\"outer_dict\":{\"inner_list\":[false,1,\"in_list\",{\"bool\":true,"
+      "\"double\":42.0,\"int\":42,\"string\":\"ab\"}]}}",
+      json);
+}
+
+TEST(TraceEventArgumentTest, PassTracedValue) {
+  auto dict_value = make_scoped_refptr(new TracedValue);
+  dict_value->SetInteger("a", 1);
+
+  auto nested_dict_value = make_scoped_refptr(new TracedValue);
+  nested_dict_value->SetInteger("b", 2);
+  nested_dict_value->BeginArray("c");
+  nested_dict_value->AppendString("foo");
+  nested_dict_value->EndArray();
+
+  dict_value->SetValue("e", *nested_dict_value);
+
+  // Check the merged result.
+  std::string json;
+  dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"a\":1,\"e\":{\"b\":2,\"c\":[\"foo\"]}}", json);
+
+  // Check that the passed nestd dict was left unouthced.
+  json = "";
+  nested_dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"]}", json);
+
+  // And that it is still usable.
+  nested_dict_value->SetInteger("f", 3);
+  nested_dict_value->BeginDictionary("g");
+  nested_dict_value->EndDictionary();
+  json = "";
+  nested_dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"],\"f\":3,\"g\":{}}", json);
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
index 28c154c..6822eff 100644
--- a/base/trace_event/trace_event_etw_export_win.cc
+++ b/base/trace_event/trace_event_etw_export_win.cc
@@ -7,12 +7,14 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
+#include "base/strings/string_tokenizer.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/platform_thread.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
+// https://github.com/google/UIforETW/tree/master/ETWProviders
 //
 // EVNTAPI is used in evntprov.h which is included by chrome_events_win.h.
 // We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can
@@ -40,6 +42,58 @@
 tEventRegister EventRegisterProc = nullptr;
 tEventWrite EventWriteProc = nullptr;
 tEventUnregister EventUnregisterProc = nullptr;
+
+// |kFilteredEventGroupNames| contains the event categories that can be
+// exported individually. These categories can be enabled by passing the correct
+// keyword when starting the trace. A keyword is a 64-bit flag and we attribute
+// one bit per category. We can therefore enable a particular category by
+// setting its corresponding bit in the keyword. For events that are not present
+// in |kFilteredEventGroupNames|, we have two bits that control their
+// behaviour. When bit 61 is enabled, any event that is not disabled by default
+// (ie. doesn't start with disabled-by-default-) will be exported. Likewise,
+// when bit 62 is enabled, any event that is disabled by default will be
+// exported.
+//
+// Note that bit 63 (MSB) must always be set, otherwise tracing will be disabled
+// by ETW. Therefore, the keyword will always be greater than
+// 0x8000000000000000.
+//
+// Examples of passing keywords to the provider using xperf:
+// # This exports "benchmark" and "cc" events
+// xperf -start chrome -on Chrome:0x8000000000000009
+//
+// # This exports "gpu", "netlog" and all other events that are not disabled by
+// # default
+// xperf -start chrome -on Chrome:0xA0000000000000A0
+//
+// More info about starting a trace and keyword can be obtained by using the
+// help section of xperf (xperf -help start). Note that xperf documentation
+// refers to keywords as flags and there are two ways to enable them, using
+// group names or the hex representation. We only support the latter. Also, we
+// ignore the level.
+const char* const kFilteredEventGroupNames[] = {
+    "benchmark",                                       // 0x1
+    "blink",                                           // 0x2
+    "browser",                                         // 0x4
+    "cc",                                              // 0x8
+    "evdev",                                           // 0x10
+    "gpu",                                             // 0x20
+    "input",                                           // 0x40
+    "netlog",                                          // 0x80
+    "renderer.scheduler",                              // 0x100
+    "toplevel",                                        // 0x200
+    "v8",                                              // 0x400
+    "disabled-by-default-cc.debug",                    // 0x800
+    "disabled-by-default-cc.debug.picture",            // 0x1000
+    "disabled-by-default-toplevel.flow",               // 0x2000
+    "startup"};                                        // 0x4000
+const char kOtherEventsGroupName[] = "__OTHER_EVENTS";  // 0x2000000000000000
+const char kDisabledOtherEventsGroupName[] =
+    "__DISABLED_OTHER_EVENTS";  // 0x4000000000000000
+const uint64 kOtherEventsKeywordBit = 1ULL << 61;
+const uint64 kDisabledOtherEventsKeywordBit = 1ULL << 62;
+const size_t kNumberOfCategories = ARRAYSIZE(kFilteredEventGroupNames) + 2U;
+
 }  // namespace
 
 // Redirector function for EventRegister. Called by macros in
@@ -51,6 +105,7 @@
   if (EventRegisterProc)
     return EventRegisterProc(ProviderId, EnableCallback, CallbackContext,
                              RegHandle);
+  *RegHandle = 0;
   return 0;
 }
 
@@ -76,7 +131,32 @@
 namespace base {
 namespace trace_event {
 
-TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
+// This object will be created by each process. It's a background (low-priority)
+// thread that will monitor the ETW keyword for any changes.
+class TraceEventETWExport::ETWKeywordUpdateThread
+    : public PlatformThread::Delegate {
+ public:
+  ETWKeywordUpdateThread() {}
+  ~ETWKeywordUpdateThread() override {}
+
+  // Implementation of PlatformThread::Delegate:
+  void ThreadMain() override {
+    PlatformThread::SetName("ETW Keyword Update Thread");
+    TimeDelta sleep_time = TimeDelta::FromMilliseconds(kUpdateTimerDelayMs);
+    while (1) {
+      PlatformThread::Sleep(sleep_time);
+      trace_event::TraceEventETWExport::UpdateETWKeyword();
+    }
+  }
+
+ private:
+  // Time between checks for ETW keyword changes (in milliseconds).
+  unsigned int kUpdateTimerDelayMs = 1000;
+};
+
+
+TraceEventETWExport::TraceEventETWExport()
+    : etw_export_enabled_(false), etw_match_any_keyword_(0ULL) {
   // Find Advapi32.dll. This should always succeed.
   HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll");
   if (AdvapiDLL) {
@@ -92,6 +172,16 @@
     // calls will fail (on XP this call will do nothing).
     EventRegisterChrome();
   }
+
+  // Make sure to initialize the map with all the group names. Subsequent
+  // modifications will be made by the background thread and only affect the
+  // values of the keys (no key addition/deletion). Therefore, the map does not
+  // require a lock for access.
+  for (int i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++)
+    categories_status_[kFilteredEventGroupNames[i]] = false;
+  categories_status_[kOtherEventsGroupName] = false;
+  categories_status_[kDisabledOtherEventsGroupName] = false;
+  DCHECK_EQ(kNumberOfCategories, categories_status_.size());
 }
 
 TraceEventETWExport::~TraceEventETWExport() {
@@ -106,14 +196,33 @@
 
 // static
 void TraceEventETWExport::EnableETWExport() {
-  if (GetInstance())
-    GetInstance()->ETWExportEnabled_ = true;
+  auto* instance = GetInstance();
+  if (instance && !instance->etw_export_enabled_) {
+    instance->etw_export_enabled_ = true;
+    // Sync the enabled categories with ETW by calling UpdateEnabledCategories()
+    // that checks the keyword. Then create a thread that will call that same
+    // function periodically, to make sure we stay in sync.
+    instance->UpdateEnabledCategories();
+    if (instance->keyword_update_thread_handle_.is_null()) {
+      instance->keyword_update_thread_.reset(new ETWKeywordUpdateThread);
+      PlatformThread::CreateWithPriority(
+          0, instance->keyword_update_thread_.get(),
+          &instance->keyword_update_thread_handle_, ThreadPriority::BACKGROUND);
+    }
+  }
 }
 
 // static
 void TraceEventETWExport::DisableETWExport() {
-  if (GetInstance())
-    GetInstance()->ETWExportEnabled_ = false;
+  auto* instance = GetInstance();
+  if (instance && instance->etw_export_enabled_)
+    instance->etw_export_enabled_ = false;
+}
+
+// static
+bool TraceEventETWExport::IsETWExportEnabled() {
+  auto* instance = GetInstance();
+  return (instance && instance->etw_export_enabled_);
 }
 
 // static
@@ -128,8 +237,8 @@
     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())
+  auto* instance = GetInstance();
+  if (!instance || !instance->etw_export_enabled_ || !EventEnabledChromeEvent())
     return;
 
   const char* phase_string = nullptr;
@@ -210,7 +319,7 @@
       // *total* process CPU time when ETW tracing, and many of the strings
       // created exceed WPA's 4094 byte limit and are shown as:
       // "Unable to parse data". See crbug.com/488257
-      //convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
+      // convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
     } else {
       TraceEvent::TraceValue trace_event;
       trace_event.as_uint = arg_values[i];
@@ -227,25 +336,101 @@
 }
 
 // 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())
+void TraceEventETWExport::AddCompleteEndEvent(const char* name) {
+  auto* instance = GetInstance();
+  if (!instance || !instance->etw_export_enabled_ || !EventEnabledChromeEvent())
     return;
 
-  EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2,
-                        arg_value_2, arg_name_3, arg_value_3);
+  EventWriteChromeEvent(name, "Complete End", "", "", "", "", "", "");
 }
 
-void TraceEventETWExport::Resurrect() {
-  StaticMemorySingletonTraits<TraceEventETWExport>::Resurrect();
+// static
+bool TraceEventETWExport::IsCategoryGroupEnabled(
+    const char* category_group_name) {
+  DCHECK(category_group_name);
+  auto* instance = GetInstance();
+  if (instance == nullptr)
+    return false;
+
+  if (!instance->IsETWExportEnabled())
+    return false;
+
+  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();
+    if (instance->IsCategoryEnabled(category_group_token.c_str())) {
+      return true;
+    }
+  }
+  return false;
 }
 
+bool TraceEventETWExport::UpdateEnabledCategories() {
+  if (etw_match_any_keyword_ == CHROME_Context.MatchAnyKeyword)
+    return false;
+
+  // If the keyword has changed, update each category.
+  // Chrome_Context.MatchAnyKeyword is set by UIforETW (or other ETW trace
+  // recording tools) using the ETW infrastructure. This value will be set in
+  // all Chrome processes that have registered their ETW provider.
+  etw_match_any_keyword_ = CHROME_Context.MatchAnyKeyword;
+  for (int i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++) {
+    if (etw_match_any_keyword_ & (1ULL << i)) {
+      categories_status_[kFilteredEventGroupNames[i]] = true;
+    } else {
+      categories_status_[kFilteredEventGroupNames[i]] = false;
+    }
+  }
+
+  // Also update the two default categories.
+  if (etw_match_any_keyword_ & kOtherEventsKeywordBit) {
+    categories_status_[kOtherEventsGroupName] = true;
+  } else {
+    categories_status_[kOtherEventsGroupName] = false;
+  }
+  if (etw_match_any_keyword_ & kDisabledOtherEventsKeywordBit) {
+    categories_status_[kDisabledOtherEventsGroupName] = true;
+  } else {
+    categories_status_[kDisabledOtherEventsGroupName] = false;
+  }
+
+  DCHECK_EQ(kNumberOfCategories, categories_status_.size());
+
+  // Update the categories in TraceLog.
+  TraceLog::GetInstance()->UpdateETWCategoryGroupEnabledFlags();
+
+  return true;
+}
+
+bool TraceEventETWExport::IsCategoryEnabled(const char* category_name) const {
+  DCHECK_EQ(kNumberOfCategories, categories_status_.size());
+  // Try to find the category and return its status if found
+  auto it = categories_status_.find(category_name);
+  if (it != categories_status_.end())
+    return it->second;
+
+  // Otherwise return the corresponding default status by first checking if the
+  // category is disabled by default.
+  if (StringPiece(category_name).starts_with("disabled-by-default")) {
+    DCHECK(categories_status_.find(kDisabledOtherEventsGroupName) !=
+           categories_status_.end());
+    return categories_status_.find(kDisabledOtherEventsGroupName)->second;
+  } else {
+    DCHECK(categories_status_.find(kOtherEventsGroupName) !=
+           categories_status_.end());
+    return categories_status_.find(kOtherEventsGroupName)->second;
+  }
+}
+
+// static
+void TraceEventETWExport::UpdateETWKeyword() {
+  if (!IsETWExportEnabled())
+    return;
+  auto* instance = GetInstance();
+  DCHECK(instance);
+  instance->UpdateEnabledCategories();
+}
 }  // 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
index eefe820..5c3ae60 100644
--- a/base/trace_event/trace_event_etw_export_win.h
+++ b/base/trace_event/trace_event_etw_export_win.h
@@ -6,14 +6,17 @@
 #ifndef BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
 #define BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
 
+#include <map>
+
 #include "base/base_export.h"
+#include "base/strings/string_piece.h"
 #include "base/trace_event/trace_event_impl.h"
 
-// Fwd.
+namespace base {
+
 template <typename Type>
 struct StaticMemorySingletonTraits;
 
-namespace base {
 namespace trace_event {
 
 class BASE_EXPORT TraceEventETWExport {
@@ -29,9 +32,9 @@
   static void EnableETWExport();
   static void DisableETWExport();
 
-  static bool isETWExportEnabled() {
-    return (GetInstance() && GetInstance()->ETWExportEnabled_);
-  }
+  // Returns true if ETW is enabled. For now, this is true if the command line
+  // flag is specified.
+  static bool IsETWExportEnabled();
 
   // Exports an event to ETW. This is mainly used in
   // TraceLog::AddTraceEventWithThreadIdAndTimestamp to export internal events.
@@ -46,26 +49,44 @@
       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);
+  // Exports an ETW event that marks the end of a complete event.
+  static void AddCompleteEndEvent(const char* name);
 
-  void Resurrect();
+  // Returns true if any category in the group is enabled.
+  static bool IsCategoryGroupEnabled(const char* category_group_name);
 
  private:
-  bool ETWExportEnabled_;
   // Ensure only the provider can construct us.
   friend struct StaticMemorySingletonTraits<TraceEventETWExport>;
+  // To have access to UpdateKeyword().
+  class ETWKeywordUpdateThread;
   TraceEventETWExport();
 
+  // Updates the list of enabled categories by consulting the ETW keyword.
+  // Returns true if there was a change, false otherwise.
+  bool UpdateEnabledCategories();
+
+  // Returns true if the category is enabled.
+  bool IsCategoryEnabled(const char* category_name) const;
+
+  // Called back by the update thread to check for potential changes to the
+  // keyword.
+  static void UpdateETWKeyword();
+
+  // True if ETW is enabled. Allows hiding the exporting behind a flag.
+  bool etw_export_enabled_;
+
+  // Maps category names to their status (enabled/disabled).
+  std::map<StringPiece, bool> categories_status_;
+
+  // Local copy of the ETW keyword.
+  uint64 etw_match_any_keyword_;
+
+  // Background thread that monitors changes to the ETW keyword and updates
+  // the enabled categories when a change occurs.
+  scoped_ptr<ETWKeywordUpdateThread> keyword_update_thread_;
+  PlatformThreadHandle keyword_update_thread_handle_;
+
   DISALLOW_COPY_AND_ASSIGN(TraceEventETWExport);
 };
 
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index 5ae7fb2..7e63f72 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -4,475 +4,22 @@
 
 #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/process/process_handle.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];
+#include "base/trace_event/trace_log.h"
 
 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
@@ -496,8 +43,8 @@
       category_group_enabled_(NULL),
       name_(NULL),
       thread_id_(0),
-      phase_(TRACE_EVENT_PHASE_BEGIN),
-      flags_(0) {
+      flags_(0),
+      phase_(TRACE_EVENT_PHASE_BEGIN) {
   for (int i = 0; i < kTraceMaxNumArgs; ++i)
     arg_names_[i] = NULL;
   memset(arg_values_, 0, sizeof(arg_values_));
@@ -511,9 +58,13 @@
   thread_timestamp_ = other.thread_timestamp_;
   duration_ = other.duration_;
   id_ = other.id_;
+  context_id_ = other.context_id_;
   category_group_enabled_ = other.category_group_enabled_;
   name_ = other.name_;
-  thread_id_ = other.thread_id_;
+  if (other.flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID)
+    process_id_ = other.process_id_;
+  else
+    thread_id_ = other.thread_id_;
   phase_ = other.phase_;
   flags_ = other.flags_;
   parameter_copy_storage_ = other.parameter_copy_storage_;
@@ -529,26 +80,30 @@
 void TraceEvent::Initialize(
     int thread_id,
     TimeTicks timestamp,
-    TimeTicks thread_timestamp,
+    ThreadTicks thread_timestamp,
     char phase,
     const unsigned char* category_group_enabled,
     const char* name,
     unsigned long long id,
+    unsigned long long context_id,
+    unsigned long long bind_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) {
+    unsigned int flags) {
   timestamp_ = timestamp;
   thread_timestamp_ = thread_timestamp;
   duration_ = TimeDelta::FromInternalValue(-1);
   id_ = id;
+  context_id_ = context_id;
   category_group_enabled_ = category_group_enabled;
   name_ = name;
   thread_id_ = thread_id;
   phase_ = phase;
   flags_ = flags;
+  bind_id_ = bind_id;
 
   // Clamp num_args since it may have been set by a third_party library.
   num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
@@ -623,10 +178,30 @@
 }
 
 void TraceEvent::UpdateDuration(const TimeTicks& now,
-                                const TimeTicks& thread_now) {
+                                const ThreadTicks& thread_now) {
   DCHECK_EQ(duration_.ToInternalValue(), -1);
   duration_ = now - timestamp_;
-  thread_duration_ = thread_now - thread_timestamp_;
+
+  // |thread_timestamp_| can be empty if the thread ticks clock wasn't
+  // initialized when it was recorded.
+  if (thread_timestamp_ != ThreadTicks())
+    thread_duration_ = thread_now - thread_timestamp_;
+}
+
+void TraceEvent::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("TraceEvent", sizeof(*this));
+
+  // TODO(primiano): parameter_copy_storage_ is refcounted and, in theory,
+  // could be shared by several events and we might overcount. In practice
+  // this is unlikely but it's worth checking.
+  if (parameter_copy_storage_)
+    overhead->AddRefCountedString(*parameter_copy_storage_.get());
+
+  for (size_t i = 0; i < kTraceMaxNumArgs; ++i) {
+    if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+      convertable_values_[i]->EstimateTraceMemoryOverhead(overhead);
+  }
 }
 
 // static
@@ -695,35 +270,66 @@
   }
 }
 
-void TraceEvent::AppendAsJSON(std::string* out) const {
+void TraceEvent::AppendAsJSON(
+    std::string* out,
+    const ArgumentFilterPredicate& argument_filter_predicate) const {
   int64 time_int64 = timestamp_.ToInternalValue();
-  int process_id = TraceLog::GetInstance()->process_id();
+  int process_id;
+  int thread_id;
+  if ((flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID) &&
+      process_id_ != kNullProcessId) {
+    process_id = process_id_;
+    thread_id = -1;
+  } else {
+    process_id = TraceLog::GetInstance()->process_id();
+    thread_id = thread_id_;
+  }
+  const char* category_group_name =
+      TraceLog::GetCategoryGroupName(category_group_enabled_);
+
   // Category group checked at category creation time.
   DCHECK(!strchr(name_, '"'));
-  StringAppendF(out,
-      "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ","
-      "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":{",
-      process_id,
-      thread_id_,
-      time_int64,
-      phase_,
-      TraceLog::GetCategoryGroupName(category_group_enabled_),
-      name_);
+  StringAppendF(out, "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64
+                     ","
+                     "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":",
+                process_id, thread_id, time_int64, phase_, category_group_name,
+                name_);
 
   // Output argument names and values, stop at first NULL argument name.
-  for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
-    if (i > 0)
-      *out += ",";
-    *out += "\"";
-    *out += arg_names_[i];
-    *out += "\":";
+  // TODO(oysteine): The dual predicates here is a bit ugly; if the filtering
+  // capabilities need to grow even more precise we should rethink this
+  // approach
+  ArgumentNameFilterPredicate argument_name_filter_predicate;
+  bool strip_args =
+      arg_names_[0] && !argument_filter_predicate.is_null() &&
+      !argument_filter_predicate.Run(category_group_name, name_,
+                                     &argument_name_filter_predicate);
 
-    if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
-      convertable_values_[i]->AppendAsTraceFormat(out);
-    else
-      AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+  if (strip_args) {
+    *out += "\"__stripped__\"";
+  } else {
+    *out += "{";
+
+    for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+      if (i > 0)
+        *out += ",";
+      *out += "\"";
+      *out += arg_names_[i];
+      *out += "\":";
+
+      if (argument_name_filter_predicate.is_null() ||
+          argument_name_filter_predicate.Run(arg_names_[i])) {
+        if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+          convertable_values_[i]->AppendAsTraceFormat(out);
+        else
+          AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+      } else {
+        *out += "\"__stripped__\"";
+      }
+    }
+
+    *out += "}";
   }
-  *out += "}";
 
   if (phase_ == TRACE_EVENT_PHASE_COMPLETE) {
     int64 duration = duration_.ToInternalValue();
@@ -752,6 +358,24 @@
   if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
     StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64>(id_));
 
+  if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
+    StringAppendF(out, ",\"bp\":\"e\"");
+
+  if ((flags_ & TRACE_EVENT_FLAG_FLOW_OUT) ||
+      (flags_ & TRACE_EVENT_FLAG_FLOW_IN)) {
+    StringAppendF(out, ",\"bind_id\":\"0x%" PRIx64 "\"",
+                  static_cast<uint64>(bind_id_));
+  }
+  if (flags_ & TRACE_EVENT_FLAG_FLOW_IN)
+    StringAppendF(out, ",\"flow_in\":true");
+  if (flags_ & TRACE_EVENT_FLAG_FLOW_OUT)
+    StringAppendF(out, ",\"flow_out\":true");
+
+  // Similar to id_, print the context_id as hex if present.
+  if (flags_ & TRACE_EVENT_FLAG_HAS_CONTEXT_ID)
+    StringAppendF(out, ",\"cid\":\"0x%" PRIx64 "\"",
+                  static_cast<uint64>(context_id_));
+
   // Instant events also output their scope.
   if (phase_ == TRACE_EVENT_PHASE_INSTANT) {
     char scope = '?';
@@ -797,1854 +421,5 @@
   }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-//
-// 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
index 50d33ca..84ef52f 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -14,9 +14,7 @@
 #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"
@@ -24,27 +22,7 @@
 #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;
+#include "base/trace_event/trace_event_memory_overhead.h"
 
 namespace base {
 
@@ -53,6 +31,13 @@
 
 namespace trace_event {
 
+typedef base::Callback<bool(const char* arg_name)> ArgumentNameFilterPredicate;
+
+typedef base::Callback<bool(const char* category_group_name,
+                            const char* event_name,
+                            ArgumentNameFilterPredicate*)>
+    ArgumentFilterPredicate;
+
 // For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
 // class must implement this interface.
 class BASE_EXPORT ConvertableToTraceFormat
@@ -64,6 +49,8 @@
   // appended.
   virtual void AppendAsTraceFormat(std::string* out) const = 0;
 
+  virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
   std::string ToString() const {
     std::string result;
     AppendAsTraceFormat(&result);
@@ -77,14 +64,17 @@
   friend class RefCounted<ConvertableToTraceFormat>;
 };
 
+const int kTraceMaxNumArgs = 2;
+
 struct TraceEventHandle {
   uint32 chunk_seq;
-  uint16 chunk_index;
-  uint16 event_index;
+  // These numbers of bits must be kept consistent with
+  // TraceBufferChunk::kMaxTrunkIndex and
+  // TraceBufferChunk::kTraceBufferChunkSize (in trace_buffer.h).
+  unsigned chunk_index : 26;
+  unsigned event_index : 6;
 };
 
-const int kTraceMaxNumArgs = 2;
-
 class BASE_EXPORT TraceEvent {
  public:
   union TraceValue {
@@ -106,24 +96,30 @@
   void Initialize(
       int thread_id,
       TimeTicks timestamp,
-      TimeTicks thread_timestamp,
+      ThreadTicks thread_timestamp,
       char phase,
       const unsigned char* category_group_enabled,
       const char* name,
       unsigned long long id,
+      unsigned long long context_id,
+      unsigned long long bind_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);
+      unsigned int flags);
 
   void Reset();
 
-  void UpdateDuration(const TimeTicks& now, const TimeTicks& thread_now);
+  void UpdateDuration(const TimeTicks& now, const ThreadTicks& thread_now);
+
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
 
   // Serialize event data to JSON
-  void AppendAsJSON(std::string* out) const;
+  void AppendAsJSON(
+      std::string* out,
+      const ArgumentFilterPredicate& argument_filter_predicate) const;
   void AppendPrettyPrinted(std::ostringstream* out) const;
 
   static void AppendValueAsJSON(unsigned char type,
@@ -131,13 +127,14 @@
                                 std::string* out);
 
   TimeTicks timestamp() const { return timestamp_; }
-  TimeTicks thread_timestamp() const { return thread_timestamp_; }
+  ThreadTicks thread_timestamp() const { return thread_timestamp_; }
   char phase() const { return phase_; }
   int thread_id() const { return thread_id_; }
   TimeDelta duration() const { return duration_; }
   TimeDelta thread_duration() const { return thread_duration_; }
   unsigned long long id() const { return id_; }
-  unsigned char flags() const { return flags_; }
+  unsigned long long context_id() const { return context_id_; }
+  unsigned int flags() const { return flags_; }
 
   // Exposed for unittesting:
 
@@ -158,665 +155,34 @@
  private:
   // Note: these are ordered by size (largest first) for optimal packing.
   TimeTicks timestamp_;
-  TimeTicks thread_timestamp_;
+  ThreadTicks thread_timestamp_;
   TimeDelta duration_;
   TimeDelta thread_duration_;
   // id_ can be used to store phase-specific data.
   unsigned long long id_;
+  // context_id_ is used to store context information.
+  unsigned long long context_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_;
+  // Depending on TRACE_EVENT_FLAG_HAS_PROCESS_ID the event will have either:
+  //  tid: thread_id_, pid: current_process_id (default case).
+  //  tid: -1, pid: process_id_ (when flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID).
+  union {
+    int thread_id_;
+    int process_id_;
+  };
+  unsigned int flags_;
+  unsigned long long bind_id_;
   unsigned char arg_types_[kTraceMaxNumArgs];
+  char phase_;
 
   DISALLOW_COPY_AND_ASSIGN(TraceEvent);
 };
 
-// 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
 
diff --git a/base/trace_event/trace_event_memory.cc b/base/trace_event/trace_event_memory.cc
deleted file mode 100644
index 8959589..0000000
--- a/base/trace_event/trace_event_memory.cc
+++ /dev/null
@@ -1,437 +0,0 @@
-// Copyright 2013 The Chromium Authors. All 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
deleted file mode 100644
index e2b3ae9..0000000
--- a/base/trace_event/trace_event_memory.h
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
-
-#include "base/base_export.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
-#include "base/trace_event/trace_event_impl.h"
-
-// TODO(jamescook): Windows support for memory tracing.
-#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && \
-    (defined(OS_LINUX) || defined(OS_ANDROID))
-#define TCMALLOC_TRACE_MEMORY_SUPPORTED 1
-#endif
-
-namespace base {
-
-class SingleThreadTaskRunner;
-
-namespace trace_event {
-
-// Watches for chrome://tracing to be enabled or disabled. When tracing is
-// enabled, also enables tcmalloc heap profiling. This class is the preferred
-// way to turn trace-base heap memory profiling on and off.
-class BASE_EXPORT TraceMemoryController
-    : public TraceLog::EnabledStateObserver {
- public:
-  typedef int (*StackGeneratorFunction)(int skip_count, void** stack);
-  typedef void (*HeapProfilerStartFunction)(StackGeneratorFunction callback);
-  typedef void (*HeapProfilerStopFunction)();
-  typedef char* (*GetHeapProfileFunction)();
-
-  // |task_runner| must be a task runner for the primary thread for the client
-  // process, e.g. the UI thread in a browser. The function pointers must be
-  // pointers to tcmalloc heap profiling functions; by avoiding direct calls to
-  // these functions we avoid a dependency on third_party/tcmalloc from base.
-  TraceMemoryController(scoped_refptr<SingleThreadTaskRunner> task_runner,
-                        HeapProfilerStartFunction heap_profiler_start_function,
-                        HeapProfilerStopFunction heap_profiler_stop_function,
-                        GetHeapProfileFunction get_heap_profile_function);
-  virtual ~TraceMemoryController();
-
-  // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
-  void OnTraceLogEnabled() override;
-  void OnTraceLogDisabled() override;
-
-  // Starts heap memory profiling.
-  void StartProfiling();
-
-  // Captures a heap profile.
-  void DumpMemoryProfile();
-
-  // If memory tracing is enabled, dumps a memory profile to the tracing system.
-  void StopProfiling();
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(TraceMemoryTest, TraceMemoryController);
-
-  bool IsTimerRunningForTest() const;
-
-  // Ensures the observer starts and stops tracing on the primary thread.
-  scoped_refptr<SingleThreadTaskRunner> task_runner_;
-
-  // Pointers to tcmalloc heap profiling functions. Allows this class to use
-  // tcmalloc functions without introducing a dependency from base to tcmalloc.
-  HeapProfilerStartFunction heap_profiler_start_function_;
-  HeapProfilerStopFunction heap_profiler_stop_function_;
-  GetHeapProfileFunction get_heap_profile_function_;
-
-  // Timer to schedule memory profile dumps.
-  RepeatingTimer<TraceMemoryController> dump_timer_;
-
-  WeakPtrFactory<TraceMemoryController> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(TraceMemoryController);
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-// A scoped context for memory tracing. Pushes the name onto a stack for
-// recording by tcmalloc heap profiling.
-class BASE_EXPORT ScopedTraceMemory {
- public:
-  struct ScopeData {
-    const char* category;
-    const char* name;
-  };
-
-  // Memory for |category| and |name| must be static, for example, literal
-  // strings in a TRACE_EVENT macro.
-  ScopedTraceMemory(const char* category, const char* name) {
-    if (!enabled_)
-      return;
-    Initialize(category, name);
-  }
-  ~ScopedTraceMemory() {
-    if (!enabled_)
-      return;
-    Destroy();
-  }
-
-  // Enables the storing of trace names on a per-thread stack.
-  static void set_enabled(bool enabled) { enabled_ = enabled; }
-
-  // Testing interface:
-  static void InitForTest();
-  static void CleanupForTest();
-  static int GetStackDepthForTest();
-  static ScopeData GetScopeDataForTest(int stack_index);
-
- private:
-  void Initialize(const char* category, const char* name);
-  void Destroy();
-
-  static bool enabled_;
-  DISALLOW_COPY_AND_ASSIGN(ScopedTraceMemory);
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-// Converts tcmalloc's heap profiler data with pseudo-stacks in |input| to
-// trace event compatible JSON and appends to |output|. Visible for testing.
-BASE_EXPORT void AppendHeapProfileAsTraceFormat(const char* input,
-                                                std::string* output);
-
-// Converts the first |line| of heap profiler data, which contains totals for
-// all allocations in a special format, into trace event compatible JSON and
-// appends to |output|. Visible for testing.
-BASE_EXPORT void AppendHeapProfileTotalsAsTraceFormat(const std::string& line,
-                                                      std::string* output);
-
-// Converts a single |line| of heap profiler data into trace event compatible
-// JSON and appends to |output|. Returns true if the line was valid and has a
-// non-zero number of current allocations. Visible for testing.
-BASE_EXPORT bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
-                                                    std::string* output);
-
-// Returns a pointer to a string given its hexadecimal address in |hex_address|.
-// Handles both 32-bit and 64-bit addresses. Returns "null" for null pointers
-// and "error" if |address| could not be parsed. Visible for testing.
-BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address);
-
-}  // namespace trace_event
-}  // namespace base
-
-// Make local variables with unique names based on the line number. Note that
-// the extra level of redirection is needed.
-#define INTERNAL_TRACE_MEMORY_ID3(line) trace_memory_unique_##line
-#define INTERNAL_TRACE_MEMORY_ID2(line) INTERNAL_TRACE_MEMORY_ID3(line)
-#define INTERNAL_TRACE_MEMORY_ID INTERNAL_TRACE_MEMORY_ID2(__LINE__)
-
-// This is the core macro that adds a scope to each TRACE_EVENT location.
-// It generates a unique local variable name using the macros above.
-#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
-#define INTERNAL_TRACE_MEMORY(category, name) \
-  base::trace_event::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(category, name);
-#else
-#define INTERNAL_TRACE_MEMORY(category, name)
-#endif  // defined(TRACE_MEMORY_SUPPORTED)
-
-// A special trace name that allows us to ignore memory allocations inside
-// the memory dump system itself. The allocations are recorded, but the
-// visualizer skips them. Must match the value in heap.js.
-#define TRACE_MEMORY_IGNORE "trace-memory-ignore"
-
-#endif  // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
diff --git a/base/trace_event/trace_event_memory_overhead.cc b/base/trace_event/trace_event_memory_overhead.cc
new file mode 100644
index 0000000..ba7207d
--- /dev/null
+++ b/base/trace_event/trace_event_memory_overhead.cc
@@ -0,0 +1,156 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+#include <algorithm>
+
+#include "base/bits.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+TraceEventMemoryOverhead::TraceEventMemoryOverhead() {
+}
+
+TraceEventMemoryOverhead::~TraceEventMemoryOverhead() {
+}
+
+void TraceEventMemoryOverhead::AddOrCreateInternal(
+    const char* object_type,
+    size_t count,
+    size_t allocated_size_in_bytes,
+    size_t resident_size_in_bytes) {
+  auto it = allocated_objects_.find(object_type);
+  if (it == allocated_objects_.end()) {
+    allocated_objects_.insert(std::make_pair(
+        object_type,
+        ObjectCountAndSize(
+            {count, allocated_size_in_bytes, resident_size_in_bytes})));
+    return;
+  }
+  it->second.count += count;
+  it->second.allocated_size_in_bytes += allocated_size_in_bytes;
+  it->second.resident_size_in_bytes += resident_size_in_bytes;
+}
+
+void TraceEventMemoryOverhead::Add(const char* object_type,
+                                   size_t allocated_size_in_bytes) {
+  Add(object_type, allocated_size_in_bytes, allocated_size_in_bytes);
+}
+
+void TraceEventMemoryOverhead::Add(const char* object_type,
+                                   size_t allocated_size_in_bytes,
+                                   size_t resident_size_in_bytes) {
+  AddOrCreateInternal(object_type, 1, allocated_size_in_bytes,
+                      resident_size_in_bytes);
+}
+
+void TraceEventMemoryOverhead::AddString(const std::string& str) {
+  // The number below are empirical and mainly based on profiling of real-world
+  // std::string implementations:
+  //  - even short string end up malloc()-inc at least 32 bytes.
+  //  - longer strings seem to malloc() multiples of 16 bytes.
+  const size_t capacity = bits::Align(str.capacity(), 16);
+  Add("std::string", sizeof(std::string) + std::max<size_t>(capacity, 32u));
+}
+
+void TraceEventMemoryOverhead::AddRefCountedString(
+    const RefCountedString& str) {
+  Add("RefCountedString", sizeof(RefCountedString));
+  AddString(str.data());
+}
+
+void TraceEventMemoryOverhead::AddValue(const Value& value) {
+  switch (value.GetType()) {
+    case Value::TYPE_NULL:
+    case Value::TYPE_BOOLEAN:
+    case Value::TYPE_INTEGER:
+    case Value::TYPE_DOUBLE:
+      Add("FundamentalValue", sizeof(Value));
+      break;
+
+    case Value::TYPE_STRING: {
+      const StringValue* string_value = nullptr;
+      value.GetAsString(&string_value);
+      Add("StringValue", sizeof(StringValue));
+      AddString(string_value->GetString());
+    } break;
+
+    case Value::TYPE_BINARY: {
+      const BinaryValue* binary_value = nullptr;
+      value.GetAsBinary(&binary_value);
+      Add("BinaryValue", sizeof(BinaryValue) + binary_value->GetSize());
+    } break;
+
+    case Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dictionary_value = nullptr;
+      value.GetAsDictionary(&dictionary_value);
+      Add("DictionaryValue", sizeof(DictionaryValue));
+      for (DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd();
+           it.Advance()) {
+        AddString(it.key());
+        AddValue(it.value());
+      }
+    } break;
+
+    case Value::TYPE_LIST: {
+      const ListValue* list_value = nullptr;
+      value.GetAsList(&list_value);
+      Add("ListValue", sizeof(ListValue));
+      for (const Value* v : *list_value)
+        AddValue(*v);
+    } break;
+
+    default:
+      NOTREACHED();
+  }
+}
+
+void TraceEventMemoryOverhead::AddSelf() {
+  size_t estimated_size = sizeof(*this);
+  // If the SmallMap did overflow its static capacity, its elements will be
+  // allocated on the heap and have to be accounted separately.
+  if (allocated_objects_.UsingFullMap())
+    estimated_size += sizeof(map_type::value_type) * allocated_objects_.size();
+  Add("TraceEventMemoryOverhead", estimated_size);
+}
+
+size_t TraceEventMemoryOverhead::GetCount(const char* object_type) const {
+  const auto& it = allocated_objects_.find(object_type);
+  if (it == allocated_objects_.end())
+    return 0u;
+  return it->second.count;
+}
+
+void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
+  for (const auto& it : other.allocated_objects_) {
+    AddOrCreateInternal(it.first, it.second.count,
+                        it.second.allocated_size_in_bytes,
+                        it.second.resident_size_in_bytes);
+  }
+}
+
+void TraceEventMemoryOverhead::DumpInto(const char* base_name,
+                                        ProcessMemoryDump* pmd) const {
+  for (const auto& it : allocated_objects_) {
+    std::string dump_name = StringPrintf("%s/%s", base_name, it.first);
+    MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name);
+    mad->AddScalar(MemoryAllocatorDump::kNameSize,
+                   MemoryAllocatorDump::kUnitsBytes,
+                   it.second.allocated_size_in_bytes);
+    mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
+                   it.second.resident_size_in_bytes);
+    mad->AddScalar(MemoryAllocatorDump::kNameObjectCount,
+                   MemoryAllocatorDump::kUnitsObjects, it.second.count);
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_memory_overhead.h b/base/trace_event/trace_event_memory_overhead.h
new file mode 100644
index 0000000..25853d1
--- /dev/null
+++ b/base/trace_event/trace_event_memory_overhead.h
@@ -0,0 +1,74 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+
+namespace base {
+
+class RefCountedString;
+class Value;
+
+namespace trace_event {
+
+class ProcessMemoryDump;
+
+// Used to estimate the memory overhead of the tracing infrastructure.
+class BASE_EXPORT TraceEventMemoryOverhead {
+ public:
+  TraceEventMemoryOverhead();
+  ~TraceEventMemoryOverhead();
+
+  // Use this method to account the overhead of an object for which an estimate
+  // is known for both the allocated and resident memory.
+  void Add(const char* object_type,
+           size_t allocated_size_in_bytes,
+           size_t resident_size_in_bytes);
+
+  // Similar to Add() above, but assumes that
+  // |resident_size_in_bytes| == |allocated_size_in_bytes|.
+  void Add(const char* object_type, size_t allocated_size_in_bytes);
+
+  // Specialized profiling functions for commonly used object types.
+  void AddString(const std::string& str);
+  void AddValue(const Value& value);
+  void AddRefCountedString(const RefCountedString& str);
+
+  // Call this after all the Add* methods above to account the memory used by
+  // this TraceEventMemoryOverhead instance itself.
+  void AddSelf();
+
+  // Retrieves the count, that is, the count of Add*(|object_type|, ...) calls.
+  size_t GetCount(const char* object_type) const;
+
+  // Adds up and merges all the values from |other| to this instance.
+  void Update(const TraceEventMemoryOverhead& other);
+
+  void DumpInto(const char* base_name, ProcessMemoryDump* pmd) const;
+
+ private:
+  struct ObjectCountAndSize {
+    size_t count;
+    size_t allocated_size_in_bytes;
+    size_t resident_size_in_bytes;
+  };
+  using map_type = SmallMap<hash_map<const char*, ObjectCountAndSize>, 16>;
+  map_type allocated_objects_;
+
+  void AddOrCreateInternal(const char* object_type,
+                           size_t count,
+                           size_t allocated_size_in_bytes,
+                           size_t resident_size_in_bytes);
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventMemoryOverhead);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
diff --git a/base/trace_event/trace_event_memory_unittest.cc b/base/trace_event/trace_event_memory_unittest.cc
deleted file mode 100644
index 781a054..0000000
--- a/base/trace_event/trace_event_memory_unittest.cc
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2013 The Chromium Authors. All 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
index bad79cc..cd0c364 100644
--- a/base/trace_event/trace_event_synthetic_delay.cc
+++ b/base/trace_event/trace_event_synthetic_delay.cc
@@ -24,7 +24,7 @@
   void ResetAllDelays();
 
   // TraceEventSyntheticDelayClock implementation.
-  base::TimeTicks Now() override;
+  TimeTicks Now() override;
 
  private:
   TraceEventSyntheticDelayRegistry();
@@ -34,7 +34,7 @@
   Lock lock_;
   TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
   TraceEventSyntheticDelay dummy_delay_;
-  base::subtle::Atomic32 delay_count_;
+  subtle::Atomic32 delay_count_;
 
   DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
 };
@@ -57,8 +57,7 @@
   clock_ = clock;
 }
 
-void TraceEventSyntheticDelay::SetTargetDuration(
-    base::TimeDelta target_duration) {
+void TraceEventSyntheticDelay::SetTargetDuration(TimeDelta target_duration) {
   AutoLock lock(lock_);
   target_duration_ = target_duration;
   trigger_count_ = 0;
@@ -85,7 +84,7 @@
   if (!target_duration_.ToInternalValue())
     return;
 
-  base::TimeTicks start_time = clock_->Now();
+  TimeTicks start_time = clock_->Now();
   {
     AutoLock lock(lock_);
     if (++begin_count_ != 1)
@@ -94,15 +93,15 @@
   }
 }
 
-void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks* out_end_time) {
+void TraceEventSyntheticDelay::BeginParallel(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();
+    *out_end_time = TimeTicks();
     return;
   }
 
-  base::TimeTicks start_time = clock_->Now();
+  TimeTicks start_time = clock_->Now();
   {
     AutoLock lock(lock_);
     *out_end_time = CalculateEndTimeLocked(start_time);
@@ -115,7 +114,7 @@
   if (!target_duration_.ToInternalValue())
     return;
 
-  base::TimeTicks end_time;
+  TimeTicks end_time;
   {
     AutoLock lock(lock_);
     if (!begin_count_ || --begin_count_ != 0)
@@ -126,21 +125,21 @@
     ApplyDelay(end_time);
 }
 
-void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
+void TraceEventSyntheticDelay::EndParallel(TimeTicks end_time) {
   if (!end_time.is_null())
     ApplyDelay(end_time);
 }
 
-base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
-    base::TimeTicks start_time) {
+TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
+    TimeTicks start_time) {
   if (mode_ == ONE_SHOT && trigger_count_++)
-    return base::TimeTicks();
+    return TimeTicks();
   else if (mode_ == ALTERNATING && trigger_count_++ % 2)
-    return base::TimeTicks();
+    return TimeTicks();
   return start_time + target_duration_;
 }
 
-void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
+void TraceEventSyntheticDelay::ApplyDelay(TimeTicks end_time) {
   TRACE_EVENT0("synthetic_delay", name_.c_str());
   while (clock_->Now() < end_time) {
     // Busy loop.
@@ -161,14 +160,14 @@
     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_);
+  int delay_count = subtle::Acquire_Load(&delay_count_);
   for (int i = 0; i < delay_count; ++i) {
     if (!strcmp(name, delays_[i].name_.c_str()))
       return &delays_[i];
   }
 
   AutoLock lock(lock_);
-  delay_count = base::subtle::Acquire_Load(&delay_count_);
+  delay_count = subtle::Acquire_Load(&delay_count_);
   for (int i = 0; i < delay_count; ++i) {
     if (!strcmp(name, delays_[i].name_.c_str()))
       return &delays_[i];
@@ -180,19 +179,19 @@
     return &dummy_delay_;
 
   delays_[delay_count].Initialize(std::string(name), this);
-  base::subtle::Release_Store(&delay_count_, delay_count + 1);
+  subtle::Release_Store(&delay_count_, delay_count + 1);
   return &delays_[delay_count];
 }
 
-base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
-  return base::TimeTicks::Now();
+TimeTicks TraceEventSyntheticDelayRegistry::Now() {
+  return TimeTicks::Now();
 }
 
 void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
   AutoLock lock(lock_);
-  int delay_count = base::subtle::Acquire_Load(&delay_count_);
+  int delay_count = subtle::Acquire_Load(&delay_count_);
   for (int i = 0; i < delay_count; ++i) {
-    delays_[i].SetTargetDuration(base::TimeDelta());
+    delays_[i].SetTargetDuration(TimeDelta());
     delays_[i].SetClock(this);
   }
 }
diff --git a/base/trace_event/trace_event_system_stats_monitor.cc b/base/trace_event/trace_event_system_stats_monitor.cc
index 98f361a..c08d9b9 100644
--- a/base/trace_event/trace_event_system_stats_monitor.cc
+++ b/base/trace_event/trace_event_system_stats_monitor.cc
@@ -125,7 +125,7 @@
 void AppendSystemProfileAsTraceFormat(const SystemMetrics& system_metrics,
                                       std::string* output) {
   std::string tmp;
-  base::JSONWriter::Write(system_metrics.ToValue().get(), &tmp);
+  base::JSONWriter::Write(*system_metrics.ToValue(), &tmp);
   *output += tmp;
 }
 
diff --git a/base/trace_event/trace_event_system_stats_monitor.h b/base/trace_event/trace_event_system_stats_monitor.h
index 051669a..0ae1f48 100644
--- a/base/trace_event/trace_event_system_stats_monitor.h
+++ b/base/trace_event/trace_event_system_stats_monitor.h
@@ -11,7 +11,7 @@
 #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"
+#include "base/trace_event/trace_log.h"
 
 namespace base {
 
@@ -33,7 +33,7 @@
   explicit TraceEventSystemStatsMonitor(
       scoped_refptr<SingleThreadTaskRunner> task_runner);
 
-  virtual ~TraceEventSystemStatsMonitor();
+  ~TraceEventSystemStatsMonitor() override;
 
   // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
   void OnTraceLogEnabled() override;
@@ -56,7 +56,7 @@
   scoped_refptr<SingleThreadTaskRunner> task_runner_;
 
   // Timer to schedule system profile dumps.
-  RepeatingTimer<TraceEventSystemStatsMonitor> dump_timer_;
+  RepeatingTimer dump_timer_;
 
   WeakPtrFactory<TraceEventSystemStatsMonitor> weak_factory_;
 
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index d032243..533a298 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -15,11 +15,13 @@
 #include "base/memory/singleton.h"
 #include "base/process/process_handle.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/pattern.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_buffer.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_synthetic_delay.h"
 #include "base/values.h"
@@ -47,6 +49,10 @@
 const char kAsyncIdStr[] = "0x5";
 const int kAsyncId2 = 6;
 const char kAsyncId2Str[] = "0x6";
+const int kFlowId = 7;
+const char kFlowIdStr[] = "0x7";
+
+const  char kRecordAllCategoryFilter[] = "*";
 
 class TraceEventTestFixture : public testing::Test {
  public:
@@ -79,13 +85,18 @@
 
   void BeginSpecificTrace(const std::string& filter) {
     event_watch_notification_ = 0;
-    TraceLog::GetInstance()->SetEnabled(
-        CategoryFilter(filter),
-        TraceLog::RECORDING_MODE,
-        TraceOptions());
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(filter, ""),
+                                        TraceLog::RECORDING_MODE);
+  }
+
+  void CancelTrace() {
+    WaitableEvent flush_complete_event(false, false);
+    CancelTraceAsync(&flush_complete_event);
+    flush_complete_event.Wait();
   }
 
   void EndTraceAndFlush() {
+    num_flush_callbacks_ = 0;
     WaitableEvent flush_complete_event(false, false);
     EndTraceAndFlushAsync(&flush_complete_event);
     flush_complete_event.Wait();
@@ -103,6 +114,13 @@
     flush_complete_event.Wait();
   }
 
+  void CancelTraceAsync(WaitableEvent* flush_complete_event) {
+    TraceLog::GetInstance()->CancelTracing(
+        base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
+                   base::Unretained(static_cast<TraceEventTestFixture*>(this)),
+                   base::Unretained(flush_complete_event)));
+  }
+
   void EndTraceAndFlushAsync(WaitableEvent* flush_complete_event) {
     TraceLog::GetInstance()->SetDisabled();
     TraceLog::GetInstance()->Flush(
@@ -134,6 +152,7 @@
     ASSERT_FALSE(tracelog->IsEnabled());
     trace_buffer_.SetOutputCallback(json_output_.GetCallback());
     event_watch_notification_ = 0;
+    num_flush_callbacks_ = 0;
   }
   void TearDown() override {
     if (TraceLog::GetInstance())
@@ -150,6 +169,7 @@
   TraceResultBuffer trace_buffer_;
   TraceResultBuffer::SimpleOutput json_output_;
   int event_watch_notification_;
+  size_t num_flush_callbacks_;
 
  private:
   // We want our singleton torn down after each test.
@@ -161,15 +181,18 @@
     WaitableEvent* flush_complete_event,
     const scoped_refptr<base::RefCountedString>& events_str,
     bool has_more_events) {
+  num_flush_callbacks_++;
+  if (num_flush_callbacks_ > 1) {
+    EXPECT_FALSE(events_str->data().empty());
+  }
   AutoLock lock(lock_);
   json_output_.json_output.clear();
   trace_buffer_.Start();
   trace_buffer_.AddFragment(events_str->data());
   trace_buffer_.Finish();
 
-  scoped_ptr<Value> root;
-  root.reset(base::JSONReader::Read(json_output_.json_output,
-                                    JSON_PARSE_RFC | JSON_DETACHABLE_CHILDREN));
+  scoped_ptr<Value> root = base::JSONReader::Read(
+      json_output_.json_output, JSON_PARSE_RFC | JSON_DETACHABLE_CHILDREN);
 
   if (!root.get()) {
     LOG(ERROR) << json_output_.json_output;
@@ -379,11 +402,6 @@
 
 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",
@@ -430,18 +448,22 @@
                            "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_EVENT_FLOW_BEGIN0("all", "TRACE_EVENT_FLOW_BEGIN0 call", kFlowId);
+    TRACE_EVENT_FLOW_STEP0("all", "TRACE_EVENT_FLOW_STEP0 call",
+                           kFlowId, "step1");
+    TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0("all",
+        "TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call", kFlowId);
 
     TRACE_COUNTER1("all", "TRACE_COUNTER1 call", 31415);
     TRACE_COUNTER2("all", "TRACE_COUNTER2 call",
                    "a", 30000,
                    "b", 1415);
 
+    TRACE_COUNTER_WITH_TIMESTAMP1("all", "TRACE_COUNTER_WITH_TIMESTAMP1 call",
+                                  42, 31415);
+    TRACE_COUNTER_WITH_TIMESTAMP2("all", "TRACE_COUNTER_WITH_TIMESTAMP2 call",
+                                  42, "a", 30000, "b", 1415);
+
     TRACE_COUNTER_ID1("all", "TRACE_COUNTER_ID1 call", 0x319009, 31415);
     TRACE_COUNTER_ID2("all", "TRACE_COUNTER_ID2 call", 0x319009,
                       "a", 30000, "b", 1415);
@@ -495,17 +517,6 @@
     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;
@@ -613,36 +624,16 @@
   EXPECT_SUB_FIND_("name2");
   EXPECT_SUB_FIND_("value2");
 
-  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW0 call");
+  EXPECT_FIND_("TRACE_EVENT_FLOW_BEGIN0 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_(kFlowIdStr);
+  EXPECT_FIND_("TRACE_EVENT_FLOW_STEP0 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_(kFlowIdStr);
+  EXPECT_SUB_FIND_("step1");
+  EXPECT_FIND_("TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 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_SUB_FIND_(kFlowIdStr);
 
   EXPECT_FIND_("TRACE_COUNTER1 call");
   {
@@ -669,6 +660,39 @@
     EXPECT_EQ(1415, value);
   }
 
+  EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP1 call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
+    EXPECT_EQ(31415, value);
+
+    int ts;
+    EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
+    EXPECT_EQ(42, ts);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP2 call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
+    EXPECT_EQ(30000, value);
+
+    EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
+    EXPECT_EQ(1415, value);
+
+    int ts;
+    EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
+    EXPECT_EQ(42, ts);
+  }
+
   EXPECT_FIND_("TRACE_COUNTER_ID1 call");
   {
     std::string id;
@@ -872,10 +896,8 @@
 
 // Simple Test for emitting data and validating it was received.
 TEST_F(TraceEventTestFixture, DataCaptured) {
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
 
   TraceWithAllMacroVariants(NULL);
 
@@ -884,6 +906,19 @@
   ValidateAllTraceMacrosCreatedData(trace_parsed_);
 }
 
+// Emit some events and validate that only empty strings are received
+// if we tell Flush() to discard events.
+TEST_F(TraceEventTestFixture, DataDiscarded) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+
+  TraceWithAllMacroVariants(NULL);
+
+  CancelTrace();
+
+  EXPECT_TRUE(trace_parsed_.empty());
+}
+
 class MockEnabledStateChangedObserver :
       public TraceLog::EnabledStateObserver {
  public:
@@ -897,10 +932,8 @@
 
   EXPECT_CALL(observer, OnTraceLogEnabled())
       .Times(1);
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
   testing::Mock::VerifyAndClear(&observer);
   EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
 
@@ -910,10 +943,8 @@
 }
 
 TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnSecondEnable) {
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
 
   testing::StrictMock<MockEnabledStateChangedObserver> observer;
   TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
@@ -922,10 +953,8 @@
       .Times(0);
   EXPECT_CALL(observer, OnTraceLogDisabled())
       .Times(0);
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
   testing::Mock::VerifyAndClear(&observer);
   EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
 
@@ -936,15 +965,9 @@
 }
 
 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());
+  TraceConfig tc_inc_all("*", "");
+  TraceLog::GetInstance()->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
+  TraceLog::GetInstance()->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
 
   testing::StrictMock<MockEnabledStateChangedObserver> observer;
   TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
@@ -962,10 +985,8 @@
 }
 
 TEST_F(TraceEventTestFixture, EnabledObserverFiresOnDisable) {
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
 
   MockEnabledStateChangedObserver observer;
   TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
@@ -984,7 +1005,7 @@
     : public TraceLog::EnabledStateObserver {
  public:
   AfterStateChangeEnabledStateObserver() {}
-  virtual ~AfterStateChangeEnabledStateObserver() {}
+  ~AfterStateChangeEnabledStateObserver() override {}
 
   // TraceLog::EnabledStateObserver overrides:
   void OnTraceLogEnabled() override {
@@ -1000,10 +1021,8 @@
   AfterStateChangeEnabledStateObserver observer;
   TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
 
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
   EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
 
   TraceLog::GetInstance()->SetDisabled();
@@ -1017,7 +1036,7 @@
     : public TraceLog::EnabledStateObserver {
  public:
   SelfRemovingEnabledStateObserver() {}
-  virtual ~SelfRemovingEnabledStateObserver() {}
+  ~SelfRemovingEnabledStateObserver() override {}
 
   // TraceLog::EnabledStateObserver overrides:
   void OnTraceLogEnabled() override {}
@@ -1034,10 +1053,8 @@
   TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
   EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
 
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
   TraceLog::GetInstance()->SetDisabled();
   // The observer removed itself on disable.
   EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
@@ -1051,10 +1068,8 @@
 
 TEST_F(TraceEventTestFixture, NewTraceRecording) {
   ASSERT_FALSE(IsNewTrace());
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
   // First call to IsNewTrace() should succeed. But, the second shouldn't.
   ASSERT_TRUE(IsNewTrace());
   ASSERT_FALSE(IsNewTrace());
@@ -1065,10 +1080,8 @@
 
   // Start another trace. IsNewTrace() should become true again, briefly, as
   // before.
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
   ASSERT_TRUE(IsNewTrace());
   ASSERT_FALSE(IsNewTrace());
 
@@ -1076,6 +1089,100 @@
   EndTraceAndFlush();
 }
 
+TEST_F(TraceEventTestFixture, TestTraceFlush) {
+  size_t min_traces = 1;
+  size_t max_traces = 1;
+  do {
+    max_traces *= 2;
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+                                        TraceLog::RECORDING_MODE);
+    for (size_t i = 0; i < max_traces; i++) {
+      TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+    }
+    EndTraceAndFlush();
+  } while (num_flush_callbacks_ < 2);
+
+  while (min_traces + 50 <  max_traces) {
+    size_t traces = (min_traces + max_traces) / 2;
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+                                        TraceLog::RECORDING_MODE);
+    for (size_t i = 0; i < traces; i++) {
+      TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+    }
+    EndTraceAndFlush();
+    if (num_flush_callbacks_ < 2) {
+      min_traces = traces - 10;
+    } else {
+      max_traces = traces + 10;
+    }
+  }
+
+  for (size_t traces = min_traces; traces < max_traces; traces++) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+                                        TraceLog::RECORDING_MODE);
+    for (size_t i = 0; i < traces; i++) {
+      TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+    }
+    EndTraceAndFlush();
+  }
+}
+
+TEST_F(TraceEventTestFixture, AddMetadataEvent) {
+  int num_calls = 0;
+
+  class Convertable : public ConvertableToTraceFormat {
+   public:
+    Convertable(int* num_calls) : num_calls_(num_calls) {}
+    void AppendAsTraceFormat(std::string* out) const override {
+      (*num_calls_)++;
+      out->append("\"metadata_value\"");
+    }
+
+   private:
+    ~Convertable() override {}
+    int* num_calls_;
+  };
+
+  scoped_refptr<ConvertableToTraceFormat> convertable =
+      new Convertable(&num_calls);
+
+  BeginTrace();
+  TRACE_EVENT_API_ADD_METADATA_EVENT("metadata_event_name", "metadata_arg_name",
+                                     convertable);
+
+  // |AppendAsTraceFormat| should only be called on flush, not when the event
+  // is added.
+  ASSERT_EQ(0, num_calls);
+  EndTraceAndFlush();
+  ASSERT_EQ(1, num_calls);
+  EXPECT_TRUE(FindNamePhaseKeyValue("metadata_event_name", "M",
+                                    "metadata_arg_name", "metadata_value"));
+
+  // The metadata event should only be adde to the current trace. In this new
+  // trace, the event should not appear.
+  BeginTrace();
+  EndTraceAndFlush();
+  ASSERT_EQ(1, num_calls);
+
+  // Flushing should cause |AppendAsTraceFormat| to be called, but if the buffer
+  // is left intact, it the flush at the end of the trace should still call it;
+  // the metadata event should not be removed.
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter,
+                  "record-until-full,enable-sampling"),
+      TraceLog::MONITORING_MODE);
+  TRACE_EVENT_API_ADD_METADATA_EVENT("metadata_event_name", "metadata_arg_name",
+                                     convertable);
+  FlushMonitoring();
+  ASSERT_EQ(2, num_calls);
+
+  // Flushing the trace at this point will case |AppendAsTraceFormat| to be
+  // called twice: once for the event that was added by the monitoring flush,
+  // and once for the end trace flush; the metadata event will be duplicated.
+  // This is consistent with the other metadata events.
+  EndTraceAndFlush();
+  ASSERT_EQ(4, num_calls);
+}
 
 // Test that categories work.
 TEST_F(TraceEventTestFixture, Categories) {
@@ -1123,10 +1230,8 @@
   // Include nonexistent category -> no events
   Clear();
   included_categories.clear();
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("not_found823564786"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("not_found823564786", ""),
+                                      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD);
   TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD);
   EndTraceAndFlush();
@@ -1136,10 +1241,8 @@
   // Include existent category -> only events of that category
   Clear();
   included_categories.clear();
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("inc"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("inc", ""),
+                                      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD);
   TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD);
   EndTraceAndFlush();
@@ -1151,9 +1254,8 @@
   Clear();
   included_categories.clear();
   TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("inc_wildcard_*,inc_wildchar_?_end"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+      TraceConfig("inc_wildcard_*,inc_wildchar_?_end", ""),
+      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("inc_wildcard_abc", "included",
       TRACE_EVENT_SCOPE_THREAD);
   TRACE_EVENT_INSTANT0("inc_wildcard_", "included", TRACE_EVENT_SCOPE_THREAD);
@@ -1181,10 +1283,8 @@
 
   // Exclude nonexistent category -> all events
   Clear();
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("-not_found823564786"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("-not_found823564786", ""),
+                                      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD);
   TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD);
   TRACE_EVENT_INSTANT0("category1,category2", "name", TRACE_EVENT_SCOPE_THREAD);
@@ -1195,10 +1295,8 @@
 
   // Exclude existent category -> only events of other categories
   Clear();
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("-inc"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("-inc", ""),
+                                      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD);
   TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD);
   TRACE_EVENT_INSTANT0("inc2,inc", "name", TRACE_EVENT_SCOPE_THREAD);
@@ -1212,9 +1310,8 @@
   // Exclude existent wildcard -> all categories not matching wildcard
   Clear();
   TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("-inc_wildcard_*,-inc_wildchar_?_end"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+      TraceConfig("-inc_wildcard_*,-inc_wildchar_?_end", ""),
+      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("inc_wildcard_abc", "not_inc",
       TRACE_EVENT_SCOPE_THREAD);
   TRACE_EVENT_INSTANT0("inc_wildcard_", "not_inc",
@@ -1368,11 +1465,13 @@
     TraceEventHandle handle1 =
         trace_event_internal::AddTraceEvent(
             TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", 0, 0,
+            trace_event_internal::kNoId,
             "arg1", std::string("argval"), "arg2", std::string("argval"));
     // Test that static TRACE_STR_COPY string arguments are copied.
     TraceEventHandle handle2 =
         trace_event_internal::AddTraceEvent(
             TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
+            trace_event_internal::kNoId,
             "arg1", TRACE_STR_COPY("argval"),
             "arg2", TRACE_STR_COPY("argval"));
     EXPECT_GT(tracer->GetStatus().event_count, 1u);
@@ -1395,6 +1494,7 @@
     TraceEventHandle handle1 =
         trace_event_internal::AddTraceEvent(
             TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", 0, 0,
+            trace_event_internal::kNoId,
             "arg1", "argval", "arg2", "argval");
     // Test that static TRACE_STR_COPY NULL string arguments are not copied.
     const char* str1 = NULL;
@@ -1402,6 +1502,7 @@
     TraceEventHandle handle2 =
         trace_event_internal::AddTraceEvent(
             TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
+            trace_event_internal::kNoId,
             "arg1", TRACE_STR_COPY(str1),
             "arg2", TRACE_STR_COPY(str2));
     EXPECT_GT(tracer->GetStatus().event_count, 1u);
@@ -1493,7 +1594,7 @@
   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();
+    thread_ids[i] = threads[i]->GetThreadId();
     threads[i]->task_runner()->PostTask(
         FROM_HERE, base::Bind(&TraceManyInstantEvents, i, kNumEvents,
                               task_complete_events[i]));
@@ -1733,22 +1834,16 @@
 
 TEST_F(TraceEventTestFixture, TraceEnableDisable) {
   TraceLog* trace_log = TraceLog::GetInstance();
-  CategoryFilter cf_inc_all("*");
-  trace_log->SetEnabled(cf_inc_all,
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  TraceConfig tc_inc_all("*", "");
+  trace_log->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
   EXPECT_TRUE(trace_log->IsEnabled());
   trace_log->SetDisabled();
   EXPECT_FALSE(trace_log->IsEnabled());
 
-  trace_log->SetEnabled(cf_inc_all,
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
   EXPECT_TRUE(trace_log->IsEnabled());
   const std::vector<std::string> empty;
-  trace_log->SetEnabled(CategoryFilter(),
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE);
   EXPECT_TRUE(trace_log->IsEnabled());
   trace_log->SetDisabled();
   EXPECT_FALSE(trace_log->IsEnabled());
@@ -1758,70 +1853,59 @@
 
 TEST_F(TraceEventTestFixture, TraceCategoriesAfterNestedEnable) {
   TraceLog* trace_log = TraceLog::GetInstance();
-  trace_log->SetEnabled(CategoryFilter("foo,bar"),
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(TraceConfig("foo,bar", ""), TraceLog::RECORDING_MODE);
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
   EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
-  trace_log->SetEnabled(CategoryFilter("foo2"),
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(TraceConfig("foo2", ""), TraceLog::RECORDING_MODE);
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo2"));
   EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
   // The "" becomes the default catergory set when applied.
-  trace_log->SetEnabled(CategoryFilter(),
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE);
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
-  EXPECT_STREQ("-*Debug,-*Test",
-               trace_log->GetCurrentCategoryFilter().ToString().c_str());
+  EXPECT_STREQ(
+    "-*Debug,-*Test",
+    trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str());
   trace_log->SetDisabled();
   trace_log->SetDisabled();
   trace_log->SetDisabled();
   EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
   EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
 
-  trace_log->SetEnabled(CategoryFilter("-foo,-bar"),
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(TraceConfig("-foo,-bar", ""), TraceLog::RECORDING_MODE);
   EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
-  trace_log->SetEnabled(CategoryFilter("moo"),
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(TraceConfig("moo", ""), TraceLog::RECORDING_MODE);
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("moo"));
   EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
-  EXPECT_STREQ("-foo,-bar",
-               trace_log->GetCurrentCategoryFilter().ToString().c_str());
+  EXPECT_STREQ(
+    "-foo,-bar",
+    trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str());
   trace_log->SetDisabled();
   trace_log->SetDisabled();
 
   // Make sure disabled categories aren't cleared if we set in the second.
-  trace_log->SetEnabled(CategoryFilter("disabled-by-default-cc,foo"),
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(TraceConfig("disabled-by-default-cc,foo", ""),
+                        TraceLog::RECORDING_MODE);
   EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("bar"));
-  trace_log->SetEnabled(CategoryFilter("disabled-by-default-gpu"),
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(TraceConfig("disabled-by-default-gpu", ""),
+                        TraceLog::RECORDING_MODE);
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-cc"));
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-gpu"));
   EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
-  EXPECT_STREQ("disabled-by-default-cc,disabled-by-default-gpu",
-               trace_log->GetCurrentCategoryFilter().ToString().c_str());
+  EXPECT_STREQ(
+    "disabled-by-default-cc,disabled-by-default-gpu",
+    trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str());
   trace_log->SetDisabled();
   trace_log->SetDisabled();
 }
 
 TEST_F(TraceEventTestFixture, TraceSampling) {
-  TraceOptions trace_options(RECORD_UNTIL_FULL);
-  trace_options.enable_sampling = true;
-  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
-                                      TraceLog::RECORDING_MODE,
-                                      trace_options);
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, "record-until-full,enable-sampling"),
+    TraceLog::RECORDING_MODE);
 
   TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "cc", "Stuff");
   TraceLog::GetInstance()->WaitSamplingEventForTesting();
@@ -1836,11 +1920,9 @@
 }
 
 TEST_F(TraceEventTestFixture, TraceSamplingScope) {
-  TraceOptions trace_options(RECORD_UNTIL_FULL);
-  trace_options.enable_sampling = true;
-  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
-                                      TraceLog::RECORDING_MODE,
-                                      trace_options);
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, "record-until-full,enable-sampling"),
+    TraceLog::RECORDING_MODE);
 
   TRACE_EVENT_SCOPED_SAMPLING_STATE("AAA", "name");
   TraceLog::GetInstance()->WaitSamplingEventForTesting();
@@ -1871,12 +1953,9 @@
 }
 
 TEST_F(TraceEventTestFixture, TraceContinuousSampling) {
-  TraceOptions trace_options(RECORD_UNTIL_FULL);
-  trace_options.enable_sampling = true;
-
-  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
-                                      TraceLog::MONITORING_MODE,
-                                      trace_options);
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, "record-until-full,enable-sampling"),
+    TraceLog::MONITORING_MODE);
 
   TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "AAA");
   TraceLog::GetInstance()->WaitSamplingEventForTesting();
@@ -1933,10 +2012,8 @@
 };
 
 TEST_F(TraceEventTestFixture, ConvertableTypes) {
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
 
   scoped_refptr<ConvertableToTraceFormat> data(new MyData());
   scoped_refptr<ConvertableToTraceFormat> data1(new MyData());
@@ -2040,10 +2117,8 @@
 }
 
 TEST_F(TraceEventTestFixture, PrimitiveArgs) {
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
 
   TRACE_EVENT1("foo", "event1", "int_one", 1);
   TRACE_EVENT1("foo", "event2", "int_neg_ten", -10);
@@ -2205,6 +2280,81 @@
   EXPECT_EQ(1, int_value);
 }
 
+namespace {
+
+bool IsArgNameWhitelisted(const char* arg_name) {
+  return base::MatchPattern(arg_name, "granular_arg_whitelisted");
+}
+
+bool IsTraceEventArgsWhitelisted(const char* category_group_name,
+                                 const char* event_name,
+                                 ArgumentNameFilterPredicate* arg_filter) {
+  if (base::MatchPattern(category_group_name, "toplevel") &&
+      base::MatchPattern(event_name, "*")) {
+    return true;
+  }
+
+  if (base::MatchPattern(category_group_name, "benchmark") &&
+      base::MatchPattern(event_name, "granularly_whitelisted")) {
+    *arg_filter = base::Bind(&IsArgNameWhitelisted);
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+TEST_F(TraceEventTestFixture, ArgsWhitelisting) {
+  TraceLog::GetInstance()->SetArgumentFilterPredicate(
+      base::Bind(&IsTraceEventArgsWhitelisted));
+
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, "enable-argument-filter"),
+    TraceLog::RECORDING_MODE);
+
+  TRACE_EVENT1("toplevel", "event1", "int_one", 1);
+  TRACE_EVENT1("whitewashed", "event2", "int_two", 1);
+
+  TRACE_EVENT2("benchmark", "granularly_whitelisted",
+               "granular_arg_whitelisted", "whitelisted_value",
+               "granular_arg_blacklisted", "blacklisted_value");
+
+  EndTraceAndFlush();
+
+  const DictionaryValue* args_dict = NULL;
+  DictionaryValue* dict = NULL;
+  int int_value;
+
+  dict = FindNamePhase("event1", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("int_one", &int_value));
+  EXPECT_EQ(1, int_value);
+
+  dict = FindNamePhase("event2", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_FALSE(args_dict->GetInteger("int_two", &int_value));
+
+  std::string args_string;
+  EXPECT_TRUE(dict->GetString("args", &args_string));
+  EXPECT_EQ(args_string, "__stripped__");
+
+  dict = FindNamePhase("granularly_whitelisted", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  EXPECT_TRUE(args_dict->GetString("granular_arg_whitelisted", &args_string));
+  EXPECT_EQ(args_string, "whitelisted_value");
+
+  EXPECT_TRUE(args_dict->GetString("granular_arg_blacklisted", &args_string));
+  EXPECT_EQ(args_string, "__stripped__");
+}
+
 class TraceEventCallbackTest : public TraceEventTestFixture {
  public:
   void SetUp() override {
@@ -2262,7 +2412,7 @@
                        const char* const arg_names[],
                        const unsigned char arg_types[],
                        const unsigned long long arg_values[],
-                       unsigned char flags) {
+                       unsigned int flags) {
     s_instance->collected_events_phases_.push_back(phase);
     s_instance->collected_events_categories_.push_back(
         TraceLog::GetCategoryGroupName(category_group_enabled));
@@ -2276,7 +2426,7 @@
 TEST_F(TraceEventCallbackTest, TraceEventCallback) {
   TRACE_EVENT_INSTANT0("all", "before enable", TRACE_EVENT_SCOPE_THREAD);
   TraceLog::GetInstance()->SetEventCallbackEnabled(
-      CategoryFilter("*"), Callback);
+      TraceConfig(kRecordAllCategoryFilter, ""), Callback);
   TRACE_EVENT_INSTANT0("all", "event1", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("all", "event2", TRACE_EVENT_SCOPE_GLOBAL);
   {
@@ -2304,15 +2454,13 @@
 }
 
 TEST_F(TraceEventCallbackTest, TraceEventCallbackWhileFull) {
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
   do {
     TRACE_EVENT_INSTANT0("all", "badger badger", TRACE_EVENT_SCOPE_GLOBAL);
   } while (!TraceLog::GetInstance()->BufferIsFull());
-  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("*"),
-                                                   Callback);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(
+      TraceConfig(kRecordAllCategoryFilter, ""), Callback);
   TRACE_EVENT_INSTANT0("all", "a snake", TRACE_EVENT_SCOPE_GLOBAL);
   TraceLog::GetInstance()->SetEventCallbackDisabled();
   ASSERT_EQ(1u, collected_events_names_.size());
@@ -2323,14 +2471,12 @@
 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"),
+  TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
                                                    Callback);
   TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("recording"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+                                      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
   TraceLog::GetInstance()->SetEventCallbackDisabled();
@@ -2348,14 +2494,12 @@
 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"),
+  TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
                                                    Callback);
   TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
-  TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("recording"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+                                      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
   EndTraceAndFlush();
@@ -2373,13 +2517,11 @@
 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());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+                                      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
-  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
+  TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
                                                    Callback);
   TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
@@ -2398,13 +2540,11 @@
 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());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+                                      TraceLog::RECORDING_MODE);
   TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
-  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
+  TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
                                                    Callback);
   TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
@@ -2420,14 +2560,12 @@
 }
 
 TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecordingDuration) {
-  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("*"),
-                                                   Callback);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(
+      TraceConfig(kRecordAllCategoryFilter, ""), Callback);
   {
     TRACE_EVENT0("callback", "duration1");
     TraceLog::GetInstance()->SetEnabled(
-        CategoryFilter("*"),
-        TraceLog::RECORDING_MODE,
-        TraceOptions());
+        TraceConfig(kRecordAllCategoryFilter, ""), TraceLog::RECORDING_MODE);
     TRACE_EVENT0("callback", "duration2");
     EndTraceAndFlush();
     TRACE_EVENT0("callback", "duration3");
@@ -2445,18 +2583,15 @@
 
 TEST_F(TraceEventTestFixture, TraceBufferVectorReportFull) {
   TraceLog* trace_log = TraceLog::GetInstance();
-  trace_log->SetEnabled(CategoryFilter("*"),
-                        TraceLog::RECORDING_MODE,
-                        TraceOptions());
+  trace_log->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, ""), TraceLog::RECORDING_MODE);
   trace_log->logged_events_.reset(
-      trace_log->CreateTraceBufferVectorOfSize(100));
+      TraceBuffer::CreateTraceBufferVectorOfSize(100));
   do {
     TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
-        "all", "with_timestamp", 0, 0,
-        TimeTicks::NowFromSystemTraceTime().ToInternalValue());
+        "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
     TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
-        "all", "with_timestamp", 0, 0,
-        TimeTicks::NowFromSystemTraceTime().ToInternalValue());
+        "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
   } while (!trace_log->BufferIsFull());
 
   EndTraceAndFlush();
@@ -2492,9 +2627,9 @@
 }
 
 TEST_F(TraceEventTestFixture, TraceBufferRingBufferGetReturnChunk) {
-  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
-                                      TraceLog::RECORDING_MODE,
-                                      TraceOptions(RECORD_CONTINUOUSLY));
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY),
+      TraceLog::RECORDING_MODE);
   TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
   size_t capacity = buffer->Capacity();
   size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
@@ -2552,9 +2687,9 @@
 }
 
 TEST_F(TraceEventTestFixture, TraceBufferRingBufferHalfIteration) {
-  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
-                                      TraceLog::RECORDING_MODE,
-                                      TraceOptions(RECORD_CONTINUOUSLY));
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY),
+      TraceLog::RECORDING_MODE);
   TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
   size_t capacity = buffer->Capacity();
   size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
@@ -2580,9 +2715,9 @@
 }
 
 TEST_F(TraceEventTestFixture, TraceBufferRingBufferFullIteration) {
-  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
-                                      TraceLog::RECORDING_MODE,
-                                      TraceOptions(RECORD_CONTINUOUSLY));
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY),
+      TraceLog::RECORDING_MODE);
   TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
   size_t capacity = buffer->Capacity();
   size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
@@ -2607,113 +2742,14 @@
 }
 
 TEST_F(TraceEventTestFixture, TraceRecordAsMuchAsPossibleMode) {
-  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
-                                      TraceLog::RECORDING_MODE,
-                                      TraceOptions(RECORD_AS_MUCH_AS_POSSIBLE));
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, RECORD_AS_MUCH_AS_POSSIBLE),
+    TraceLog::RECORDING_MODE);
   TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
   EXPECT_EQ(512000000UL, buffer->Capacity());
   TraceLog::GetInstance()->SetDisabled();
 }
 
-// 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();
@@ -2747,41 +2783,43 @@
   thread.Stop();
 }
 
-TEST_F(TraceEventTestFixture, ConvertTraceOptionsToInternalOptions) {
+TEST_F(TraceEventTestFixture, ConvertTraceConfigToInternalOptions) {
   TraceLog* trace_log = TraceLog::GetInstance();
-  TraceOptions options(RECORD_UNTIL_FULL);
   EXPECT_EQ(TraceLog::kInternalRecordUntilFull,
-            trace_log->GetInternalOptionsFromTraceOptions(options));
+            trace_log->GetInternalOptionsFromTraceConfig(
+                TraceConfig(kRecordAllCategoryFilter, RECORD_UNTIL_FULL)));
 
-  options.record_mode = RECORD_CONTINUOUSLY;
   EXPECT_EQ(TraceLog::kInternalRecordContinuously,
-            trace_log->GetInternalOptionsFromTraceOptions(options));
+            trace_log->GetInternalOptionsFromTraceConfig(
+                TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY)));
 
-  options.record_mode = ECHO_TO_CONSOLE;
   EXPECT_EQ(TraceLog::kInternalEchoToConsole,
-            trace_log->GetInternalOptionsFromTraceOptions(options));
+            trace_log->GetInternalOptionsFromTraceConfig(
+                TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE)));
 
-  options.enable_sampling = true;
-
-  options.record_mode = RECORD_UNTIL_FULL;
   EXPECT_EQ(
       TraceLog::kInternalRecordUntilFull | TraceLog::kInternalEnableSampling,
-      trace_log->GetInternalOptionsFromTraceOptions(options));
+      trace_log->GetInternalOptionsFromTraceConfig(
+          TraceConfig(kRecordAllCategoryFilter,
+                      "record-until-full,enable-sampling")));
 
-  options.record_mode = RECORD_CONTINUOUSLY;
   EXPECT_EQ(
       TraceLog::kInternalRecordContinuously | TraceLog::kInternalEnableSampling,
-      trace_log->GetInternalOptionsFromTraceOptions(options));
+      trace_log->GetInternalOptionsFromTraceConfig(
+          TraceConfig(kRecordAllCategoryFilter,
+                      "record-continuously,enable-sampling")));
 
-  options.record_mode = ECHO_TO_CONSOLE;
   EXPECT_EQ(
       TraceLog::kInternalEchoToConsole | TraceLog::kInternalEnableSampling,
-      trace_log->GetInternalOptionsFromTraceOptions(options));
+      trace_log->GetInternalOptionsFromTraceConfig(
+          TraceConfig(kRecordAllCategoryFilter,
+                      "trace-to-console,enable-sampling")));
 
-  options.enable_systrace = true;
   EXPECT_EQ(
       TraceLog::kInternalEchoToConsole | TraceLog::kInternalEnableSampling,
-      trace_log->GetInternalOptionsFromTraceOptions(options));
+      trace_log->GetInternalOptionsFromTraceConfig(
+          TraceConfig("*",
+                      "trace-to-console,enable-sampling,enable-systrace")));
 }
 
 void SetBlockingFlagAndBlockUntilStopped(WaitableEvent* task_start_event,
@@ -2876,9 +2914,8 @@
   logging::SetLogMessageHandler(MockLogMessageHandler);
 
   TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions(ECHO_TO_CONSOLE));
+      TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE),
+      TraceLog::RECORDING_MODE);
   TRACE_EVENT_BEGIN0("a", "begin_end");
   {
     TRACE_EVENT0("b", "duration");
@@ -2913,9 +2950,8 @@
   logging::SetLogMessageHandler(LogMessageHandlerWithTraceEvent);
 
   TraceLog::GetInstance()->SetEnabled(
-      CategoryFilter("*"),
-      TraceLog::RECORDING_MODE,
-      TraceOptions(ECHO_TO_CONSOLE));
+      TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE),
+      TraceLog::RECORDING_MODE);
   {
     // This should not cause deadlock or infinite recursion.
     TRACE_EVENT0("b", "duration");
@@ -2928,7 +2964,7 @@
 TEST_F(TraceEventTestFixture, TimeOffset) {
   BeginTrace();
   // Let TraceLog timer start from 0.
-  TimeDelta time_offset = TimeTicks::NowFromSystemTraceTime() - TimeTicks();
+  TimeDelta time_offset = TimeTicks::Now() - TimeTicks();
   TraceLog::GetInstance()->SetTimeOffset(time_offset);
 
   {
@@ -2936,17 +2972,15 @@
     TRACE_EVENT0("all", "duration2");
   }
   TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
-      "all", "with_timestamp", 0, 0,
-      TimeTicks::NowFromSystemTraceTime().ToInternalValue());
+      "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
   TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
-      "all", "with_timestamp", 0, 0,
-      TimeTicks::NowFromSystemTraceTime().ToInternalValue());
+      "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
 
   EndTraceAndFlush();
   DropTracedMetadataRecords();
 
   double end_time = static_cast<double>(
-      (TimeTicks::NowFromSystemTraceTime() - time_offset).ToInternalValue());
+      (TimeTicks::Now() - time_offset).ToInternalValue());
   double last_timestamp = 0;
   for (size_t i = 0; i < trace_parsed_.GetSize(); ++i) {
     const DictionaryValue* item;
@@ -2973,7 +3007,7 @@
 }
 
 TEST_F(TraceEventTestFixture, BadSyntheticDelayConfigurations) {
-  const char* const configs[] = {
+  const char* const filters[] = {
     "",
     "DELAY(",
     "DELAY(;",
@@ -2981,103 +3015,25 @@
     "DELAY(test.Delay)",
     "DELAY(test.Delay;)"
   };
-  for (size_t i = 0; i < arraysize(configs); i++) {
-    BeginSpecificTrace(configs[i]);
+  for (size_t i = 0; i < arraysize(filters); i++) {
+    BeginSpecificTrace(filters[i]);
     EndTraceAndFlush();
-    CategoryFilter filter = TraceLog::GetInstance()->GetCurrentCategoryFilter();
-    EXPECT_EQ(0u, filter.GetSyntheticDelayValues().size());
+    TraceConfig trace_config = TraceLog::GetInstance()->GetCurrentTraceConfig();
+    EXPECT_EQ(0u, trace_config.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());
+  TraceConfig config1("DELAY(test.Delay1;16)", "");
+  TraceConfig config2("DELAY(test.Delay2;32)", "");
+  config1.Merge(config2);
+  EXPECT_EQ(2u, config1.GetSyntheticDelayValues().size());
 }
 
 TEST_F(TraceEventTestFixture, SyntheticDelayConfigurationToString) {
-  const char 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);
-      }
-    }
-  }
+  const char filter[] = "DELAY(test.Delay;16;oneshot)";
+  TraceConfig config(filter, "");
+  EXPECT_EQ(filter, config.ToCategoryFilterString());
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/trace_event_win.cc b/base/trace_event/trace_event_win.cc
deleted file mode 100644
index ebb55c8..0000000
--- a/base/trace_event/trace_event_win.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All 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
deleted file mode 100644
index 4161361..0000000
--- a/base/trace_event/trace_event_win.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All 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
deleted file mode 100644
index d4dc854..0000000
--- a/base/trace_event/trace_event_win_unittest.cc
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All 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/trace_log.cc b/base/trace_event/trace_log.cc
new file mode 100644
index 0000000..791d9a2
--- /dev/null
+++ b/base/trace_event/trace_log.cc
@@ -0,0 +1,1779 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_log.h"
+
+#include <algorithm>
+#include <cmath>
+#include <utility>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/leak_annotations.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/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/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+#include "base/trace_event/trace_log.h"
+#include "base/trace_event/trace_sampling_thread.h"
+
+#if defined(OS_WIN)
+#include "base/trace_event/trace_event_etw_export_win.h"
+#endif
+
+// The thread buckets for the sampling profiler.
+BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+
+namespace base {
+namespace internal {
+
+class DeleteTraceLogForTesting {
+ public:
+  static void Delete() {
+    Singleton<trace_event::TraceLog,
+              LeakySingletonTraits<trace_event::TraceLog>>::OnExit(0);
+  }
+};
+
+}  // namespace internal
+
+namespace trace_event {
+
+namespace {
+
+// Controls the number of trace events we will buffer in-memory
+// before throwing them away.
+const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize;
+
+const size_t kTraceEventVectorBigBufferChunks =
+    512000000 / kTraceBufferChunkSize;
+static_assert(
+    kTraceEventVectorBigBufferChunks <= TraceBufferChunk::kMaxChunkIndex,
+    "Too many big buffer chunks");
+const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize;
+static_assert(
+    kTraceEventVectorBufferChunks <= TraceBufferChunk::kMaxChunkIndex,
+    "Too many vector buffer chunks");
+const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4;
+
+// 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 size_t kTraceEventBufferSizeInBytes = 100 * 1024;
+const int kThreadFlushTimeoutMs = 3000;
+
+#if !defined(OS_NACL)
+// These categories will cause deadlock when ECHO_TO_CONSOLE. crbug.com/325575.
+const char kEchoToConsoleCategoryFilter[] = "-ipc,-task";
+#endif
+
+#define MAX_CATEGORY_GROUPS 100
+
+// Parallel arrays g_category_groups and g_category_group_enabled are separate
+// so that a pointer to a member of g_category_group_enabled can be easily
+// converted to an index into g_category_groups. This allows macros to deal
+// only with char enabled pointers from g_category_group_enabled, and we can
+// convert internally to determine the category name from the char enabled
+// pointer.
+const char* g_category_groups[MAX_CATEGORY_GROUPS] = {
+    "toplevel",
+    "tracing already shutdown",
+    "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS",
+    "__metadata"};
+
+// The enabled flag is char instead of bool so that the API can be used from C.
+unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = {0};
+// Indexes here have to match the g_category_groups array indexes above.
+const int g_category_already_shutdown = 1;
+const int g_category_categories_exhausted = 2;
+const int g_category_metadata = 3;
+const int g_num_builtin_categories = 4;
+// Skip default categories.
+base::subtle::AtomicWord g_category_index = g_num_builtin_categories;
+
+// The name of the current thread. This is used to decide if the current
+// thread name has changed. We combine all the seen thread names into the
+// output name for the thread.
+LazyInstance<ThreadLocalPointer<const char>>::Leaky g_current_thread_name =
+    LAZY_INSTANCE_INITIALIZER;
+
+ThreadTicks ThreadNow() {
+  return ThreadTicks::IsSupported() ? ThreadTicks::Now() : ThreadTicks();
+}
+
+template <typename T>
+void InitializeMetadataEvent(TraceEvent* trace_event,
+                             int thread_id,
+                             const char* metadata_name,
+                             const char* arg_name,
+                             const T& value) {
+  if (!trace_event)
+    return;
+
+  int num_args = 1;
+  unsigned char arg_type;
+  unsigned long long arg_value;
+  ::trace_event_internal::SetTraceValue(value, &arg_type, &arg_value);
+  trace_event->Initialize(
+      thread_id,
+      TimeTicks(),
+      ThreadTicks(),
+      TRACE_EVENT_PHASE_METADATA,
+      &g_category_group_enabled[g_category_metadata],
+      metadata_name,
+      trace_event_internal::kNoId,  // id
+      trace_event_internal::kNoId,  // context_id
+      trace_event_internal::kNoId,  // bind_id
+      num_args,
+      &arg_name,
+      &arg_type,
+      &arg_value,
+      nullptr,
+      TRACE_EVENT_FLAG_NONE);
+}
+
+class AutoThreadLocalBoolean {
+ public:
+  explicit AutoThreadLocalBoolean(ThreadLocalBoolean* thread_local_boolean)
+      : thread_local_boolean_(thread_local_boolean) {
+    DCHECK(!thread_local_boolean_->Get());
+    thread_local_boolean_->Set(true);
+  }
+  ~AutoThreadLocalBoolean() { thread_local_boolean_->Set(false); }
+
+ private:
+  ThreadLocalBoolean* thread_local_boolean_;
+  DISALLOW_COPY_AND_ASSIGN(AutoThreadLocalBoolean);
+};
+
+// Use this function instead of TraceEventHandle constructor to keep the
+// overhead of ScopedTracer (trace_event.h) constructor minimum.
+void MakeHandle(uint32 chunk_seq,
+                size_t chunk_index,
+                size_t event_index,
+                TraceEventHandle* handle) {
+  DCHECK(chunk_seq);
+  DCHECK(chunk_index <= TraceBufferChunk::kMaxChunkIndex);
+  DCHECK(event_index < TraceBufferChunk::kTraceBufferChunkSize);
+  handle->chunk_seq = chunk_seq;
+  handle->chunk_index = static_cast<uint16>(chunk_index);
+  handle->event_index = static_cast<uint16>(event_index);
+}
+
+}  // namespace
+
+// A helper class that allows the lock to be acquired in the middle of the scope
+// and unlocks at the end of scope if locked.
+class TraceLog::OptionalAutoLock {
+ public:
+  explicit OptionalAutoLock(Lock* lock) : lock_(lock), locked_(false) {}
+
+  ~OptionalAutoLock() {
+    if (locked_)
+      lock_->Release();
+  }
+
+  void EnsureAcquired() {
+    if (!locked_) {
+      lock_->Acquire();
+      locked_ = true;
+    }
+  }
+
+ private:
+  Lock* lock_;
+  bool locked_;
+  DISALLOW_COPY_AND_ASSIGN(OptionalAutoLock);
+};
+
+class TraceLog::ThreadLocalEventBuffer
+    : public MessageLoop::DestructionObserver,
+      public MemoryDumpProvider {
+ public:
+  ThreadLocalEventBuffer(TraceLog* trace_log);
+  ~ThreadLocalEventBuffer() override;
+
+  TraceEvent* AddTraceEvent(TraceEventHandle* handle);
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) {
+    if (!chunk_ || handle.chunk_seq != chunk_->seq() ||
+        handle.chunk_index != chunk_index_)
+      return NULL;
+
+    return chunk_->GetEventAt(handle.event_index);
+  }
+
+  int generation() const { return generation_; }
+
+ private:
+  // MessageLoop::DestructionObserver
+  void WillDestroyCurrentMessageLoop() override;
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override;
+
+  void FlushWhileLocked();
+
+  void CheckThisIsCurrentBuffer() const {
+    DCHECK(trace_log_->thread_local_event_buffer_.Get() == this);
+  }
+
+  // Since TraceLog is a leaky singleton, trace_log_ will always be valid
+  // as long as the thread exists.
+  TraceLog* trace_log_;
+  scoped_ptr<TraceBufferChunk> chunk_;
+  size_t chunk_index_;
+  int generation_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalEventBuffer);
+};
+
+TraceLog::ThreadLocalEventBuffer::ThreadLocalEventBuffer(TraceLog* trace_log)
+    : trace_log_(trace_log),
+      chunk_index_(0),
+      generation_(trace_log->generation()) {
+  // ThreadLocalEventBuffer is created only if the thread has a message loop, so
+  // the following message_loop won't be NULL.
+  MessageLoop* message_loop = MessageLoop::current();
+  message_loop->AddDestructionObserver(this);
+
+  // This is to report the local memory usage when memory-infra is enabled.
+  MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      this, "ThreadLocalEventBuffer", ThreadTaskRunnerHandle::Get());
+
+  AutoLock lock(trace_log->lock_);
+  trace_log->thread_message_loops_.insert(message_loop);
+}
+
+TraceLog::ThreadLocalEventBuffer::~ThreadLocalEventBuffer() {
+  CheckThisIsCurrentBuffer();
+  MessageLoop::current()->RemoveDestructionObserver(this);
+  MemoryDumpManager::GetInstance()->UnregisterDumpProvider(this);
+
+  {
+    AutoLock lock(trace_log_->lock_);
+    FlushWhileLocked();
+    trace_log_->thread_message_loops_.erase(MessageLoop::current());
+  }
+  trace_log_->thread_local_event_buffer_.Set(NULL);
+}
+
+TraceEvent* TraceLog::ThreadLocalEventBuffer::AddTraceEvent(
+    TraceEventHandle* handle) {
+  CheckThisIsCurrentBuffer();
+
+  if (chunk_ && chunk_->IsFull()) {
+    AutoLock lock(trace_log_->lock_);
+    FlushWhileLocked();
+    chunk_.reset();
+  }
+  if (!chunk_) {
+    AutoLock lock(trace_log_->lock_);
+    chunk_ = trace_log_->logged_events_->GetChunk(&chunk_index_);
+    trace_log_->CheckIfBufferIsFullWhileLocked();
+  }
+  if (!chunk_)
+    return NULL;
+
+  size_t event_index;
+  TraceEvent* trace_event = chunk_->AddTraceEvent(&event_index);
+  if (trace_event && handle)
+    MakeHandle(chunk_->seq(), chunk_index_, event_index, handle);
+
+  return trace_event;
+}
+
+void TraceLog::ThreadLocalEventBuffer::WillDestroyCurrentMessageLoop() {
+  delete this;
+}
+
+bool TraceLog::ThreadLocalEventBuffer::OnMemoryDump(const MemoryDumpArgs& args,
+                                                    ProcessMemoryDump* pmd) {
+  if (!chunk_)
+    return true;
+  std::string dump_base_name = StringPrintf(
+      "tracing/thread_%d", static_cast<int>(PlatformThread::CurrentId()));
+  TraceEventMemoryOverhead overhead;
+  chunk_->EstimateTraceMemoryOverhead(&overhead);
+  overhead.DumpInto(dump_base_name.c_str(), pmd);
+  return true;
+}
+
+void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
+  if (!chunk_)
+    return;
+
+  trace_log_->lock_.AssertAcquired();
+  if (trace_log_->CheckGeneration(generation_)) {
+    // Return the chunk to the buffer only if the generation matches.
+    trace_log_->logged_events_->ReturnChunk(chunk_index_, std::move(chunk_));
+  }
+  // Otherwise this method may be called from the destructor, or TraceLog will
+  // find the generation mismatch and delete this buffer soon.
+}
+
+TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {}
+
+TraceLogStatus::~TraceLogStatus() {}
+
+// static
+TraceLog* TraceLog::GetInstance() {
+  return Singleton<TraceLog, LeakySingletonTraits<TraceLog>>::get();
+}
+
+TraceLog::TraceLog()
+    : mode_(DISABLED),
+      num_traces_recorded_(0),
+      event_callback_(0),
+      dispatching_to_observer_list_(false),
+      process_sort_index_(0),
+      process_id_hash_(0),
+      process_id_(0),
+      watch_category_(0),
+      trace_options_(kInternalRecordUntilFull),
+      sampling_thread_handle_(0),
+      trace_config_(TraceConfig()),
+      event_callback_trace_config_(TraceConfig()),
+      thread_shared_chunk_index_(0),
+      generation_(0),
+      use_worker_thread_(false) {
+  // Trace is enabled or disabled on one thread while other threads are
+  // accessing the enabled flag. We don't care whether edge-case events are
+  // traced or not, so we allow races on the enabled flag to keep the trace
+  // macros fast.
+  // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots:
+  // ANNOTATE_BENIGN_RACE_SIZED(g_category_group_enabled,
+  //                            sizeof(g_category_group_enabled),
+  //                           "trace_event category enabled");
+  for (int i = 0; i < MAX_CATEGORY_GROUPS; ++i) {
+    ANNOTATE_BENIGN_RACE(&g_category_group_enabled[i],
+                         "trace_event category enabled");
+  }
+#if defined(OS_NACL)  // NaCl shouldn't expose the process id.
+  SetProcessID(0);
+#else
+  SetProcessID(static_cast<int>(GetCurrentProcId()));
+
+  // NaCl also shouldn't access the command line.
+  if (CommandLine::InitializedForCurrentProcess() &&
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToConsole)) {
+    std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+        switches::kTraceToConsole);
+    if (filter.empty()) {
+      filter = kEchoToConsoleCategoryFilter;
+    } else {
+      filter.append(",");
+      filter.append(kEchoToConsoleCategoryFilter);
+    }
+
+    LOG(ERROR) << "Start " << switches::kTraceToConsole
+               << " with CategoryFilter '" << filter << "'.";
+    SetEnabled(TraceConfig(filter, ECHO_TO_CONSOLE), RECORDING_MODE);
+  }
+#endif
+
+  logged_events_.reset(CreateTraceBuffer());
+
+  MemoryDumpManager::GetInstance()->RegisterDumpProvider(this, "TraceLog",
+                                                         nullptr);
+}
+
+TraceLog::~TraceLog() {}
+
+void TraceLog::InitializeThreadLocalEventBufferIfSupported() {
+  // A ThreadLocalEventBuffer needs the message loop
+  // - to know when the thread exits;
+  // - to handle the final flush.
+  // For a thread without a message loop or the message loop may be blocked, the
+  // trace events will be added into the main buffer directly.
+  if (thread_blocks_message_loop_.Get() || !MessageLoop::current())
+    return;
+  auto thread_local_event_buffer = thread_local_event_buffer_.Get();
+  if (thread_local_event_buffer &&
+      !CheckGeneration(thread_local_event_buffer->generation())) {
+    delete thread_local_event_buffer;
+    thread_local_event_buffer = NULL;
+  }
+  if (!thread_local_event_buffer) {
+    thread_local_event_buffer = new ThreadLocalEventBuffer(this);
+    thread_local_event_buffer_.Set(thread_local_event_buffer);
+  }
+}
+
+bool TraceLog::OnMemoryDump(const MemoryDumpArgs& args,
+                            ProcessMemoryDump* pmd) {
+  // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested
+  // (crbug.com/499731).
+  TraceEventMemoryOverhead overhead;
+  overhead.Add("TraceLog", sizeof(*this));
+  {
+    AutoLock lock(lock_);
+    if (logged_events_)
+      logged_events_->EstimateTraceMemoryOverhead(&overhead);
+
+    for (auto& metadata_event : metadata_events_)
+      metadata_event->EstimateTraceMemoryOverhead(&overhead);
+  }
+  overhead.AddSelf();
+  overhead.DumpInto("tracing/main_trace_log", pmd);
+  return true;
+}
+
+const unsigned char* TraceLog::GetCategoryGroupEnabled(
+    const char* category_group) {
+  TraceLog* tracelog = GetInstance();
+  if (!tracelog) {
+    DCHECK(!g_category_group_enabled[g_category_already_shutdown]);
+    return &g_category_group_enabled[g_category_already_shutdown];
+  }
+  return tracelog->GetCategoryGroupEnabledInternal(category_group);
+}
+
+const char* TraceLog::GetCategoryGroupName(
+    const unsigned char* category_group_enabled) {
+  // Calculate the index of the category group by finding
+  // category_group_enabled in g_category_group_enabled array.
+  uintptr_t category_begin =
+      reinterpret_cast<uintptr_t>(g_category_group_enabled);
+  uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
+  DCHECK(category_ptr >= category_begin &&
+         category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
+                                                    MAX_CATEGORY_GROUPS))
+      << "out of bounds category pointer";
+  uintptr_t category_index =
+      (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
+  return g_category_groups[category_index];
+}
+
+void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
+  unsigned char enabled_flag = 0;
+  const char* category_group = g_category_groups[category_index];
+  if (mode_ == RECORDING_MODE &&
+      trace_config_.IsCategoryGroupEnabled(category_group))
+    enabled_flag |= ENABLED_FOR_RECORDING;
+  else if (mode_ == MONITORING_MODE &&
+           trace_config_.IsCategoryGroupEnabled(category_group))
+    enabled_flag |= ENABLED_FOR_MONITORING;
+  if (event_callback_ &&
+      event_callback_trace_config_.IsCategoryGroupEnabled(category_group))
+    enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
+#if defined(OS_WIN)
+  if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
+          category_group)) {
+    enabled_flag |= ENABLED_FOR_ETW_EXPORT;
+  }
+#endif
+
+  g_category_group_enabled[category_index] = enabled_flag;
+}
+
+void TraceLog::UpdateCategoryGroupEnabledFlags() {
+  size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+  for (size_t i = 0; i < category_index; i++)
+    UpdateCategoryGroupEnabledFlag(i);
+}
+
+void TraceLog::UpdateSyntheticDelaysFromTraceConfig() {
+  ResetTraceEventSyntheticDelays();
+  const TraceConfig::StringList& delays =
+      trace_config_.GetSyntheticDelayValues();
+  TraceConfig::StringList::const_iterator ci;
+  for (ci = delays.begin(); ci != delays.end(); ++ci) {
+    StringTokenizer tokens(*ci, ";");
+    if (!tokens.GetNext())
+      continue;
+    TraceEventSyntheticDelay* delay =
+        TraceEventSyntheticDelay::Lookup(tokens.token());
+    while (tokens.GetNext()) {
+      std::string token = tokens.token();
+      char* duration_end;
+      double target_duration = strtod(token.c_str(), &duration_end);
+      if (duration_end != token.c_str()) {
+        delay->SetTargetDuration(TimeDelta::FromMicroseconds(
+            static_cast<int64>(target_duration * 1e6)));
+      } else if (token == "static") {
+        delay->SetMode(TraceEventSyntheticDelay::STATIC);
+      } else if (token == "oneshot") {
+        delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
+      } else if (token == "alternating") {
+        delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
+      }
+    }
+  }
+}
+
+const unsigned char* TraceLog::GetCategoryGroupEnabledInternal(
+    const char* category_group) {
+  DCHECK(!strchr(category_group, '"'))
+      << "Category groups may not contain double quote";
+  // The g_category_groups is append only, avoid using a lock for the fast path.
+  size_t current_category_index = base::subtle::Acquire_Load(&g_category_index);
+
+  // Search for pre-existing category group.
+  for (size_t i = 0; i < current_category_index; ++i) {
+    if (strcmp(g_category_groups[i], category_group) == 0) {
+      return &g_category_group_enabled[i];
+    }
+  }
+
+  unsigned char* category_group_enabled = NULL;
+  // This is the slow path: the lock is not held in the case above, so more
+  // than one thread could have reached here trying to add the same category.
+  // Only hold to lock when actually appending a new category, and
+  // check the categories groups again.
+  AutoLock lock(lock_);
+  size_t category_index = base::subtle::Acquire_Load(&g_category_index);
+  for (size_t i = 0; i < category_index; ++i) {
+    if (strcmp(g_category_groups[i], category_group) == 0) {
+      return &g_category_group_enabled[i];
+    }
+  }
+
+  // Create a new category group.
+  DCHECK(category_index < MAX_CATEGORY_GROUPS)
+      << "must increase MAX_CATEGORY_GROUPS";
+  if (category_index < MAX_CATEGORY_GROUPS) {
+    // Don't hold on to the category_group pointer, so that we can create
+    // category groups with strings not known at compile time (this is
+    // required by SetWatchEvent).
+    const char* new_group = strdup(category_group);
+    ANNOTATE_LEAKING_OBJECT_PTR(new_group);
+    g_category_groups[category_index] = new_group;
+    DCHECK(!g_category_group_enabled[category_index]);
+    // Note that if both included and excluded patterns in the
+    // TraceConfig are empty, we exclude nothing,
+    // thereby enabling this category group.
+    UpdateCategoryGroupEnabledFlag(category_index);
+    category_group_enabled = &g_category_group_enabled[category_index];
+    // Update the max index now.
+    base::subtle::Release_Store(&g_category_index, category_index + 1);
+  } else {
+    category_group_enabled =
+        &g_category_group_enabled[g_category_categories_exhausted];
+  }
+  return category_group_enabled;
+}
+
+void TraceLog::GetKnownCategoryGroups(
+    std::vector<std::string>* category_groups) {
+  AutoLock lock(lock_);
+  size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+  for (size_t i = g_num_builtin_categories; i < category_index; i++)
+    category_groups->push_back(g_category_groups[i]);
+}
+
+void TraceLog::SetEnabled(const TraceConfig& trace_config, Mode mode) {
+  std::vector<EnabledStateObserver*> observer_list;
+  {
+    AutoLock lock(lock_);
+
+    // Can't enable tracing when Flush() is in progress.
+    DCHECK(!flush_task_runner_);
+
+    InternalTraceOptions new_options =
+        GetInternalOptionsFromTraceConfig(trace_config);
+
+    InternalTraceOptions old_options = trace_options();
+
+    if (IsEnabled()) {
+      if (new_options != old_options) {
+        DLOG(ERROR) << "Attempting to re-enable tracing with a different "
+                    << "set of options.";
+      }
+
+      if (mode != mode_) {
+        DLOG(ERROR) << "Attempting to re-enable tracing with a different mode.";
+      }
+
+      trace_config_.Merge(trace_config);
+      UpdateCategoryGroupEnabledFlags();
+      return;
+    }
+
+    if (dispatching_to_observer_list_) {
+      DLOG(ERROR)
+          << "Cannot manipulate TraceLog::Enabled state from an observer.";
+      return;
+    }
+
+    mode_ = mode;
+
+    if (new_options != old_options) {
+      subtle::NoBarrier_Store(&trace_options_, new_options);
+      UseNextTraceBuffer();
+    }
+
+    num_traces_recorded_++;
+
+    trace_config_ = TraceConfig(trace_config);
+    UpdateCategoryGroupEnabledFlags();
+    UpdateSyntheticDelaysFromTraceConfig();
+
+    if (new_options & kInternalEnableSampling) {
+      sampling_thread_.reset(new TraceSamplingThread);
+      sampling_thread_->RegisterSampleBucket(
+          &g_trace_state[0], "bucket0",
+          Bind(&TraceSamplingThread::DefaultSamplingCallback));
+      sampling_thread_->RegisterSampleBucket(
+          &g_trace_state[1], "bucket1",
+          Bind(&TraceSamplingThread::DefaultSamplingCallback));
+      sampling_thread_->RegisterSampleBucket(
+          &g_trace_state[2], "bucket2",
+          Bind(&TraceSamplingThread::DefaultSamplingCallback));
+      if (!PlatformThread::Create(0, sampling_thread_.get(),
+                                  &sampling_thread_handle_)) {
+        DCHECK(false) << "failed to create thread";
+      }
+    }
+
+    dispatching_to_observer_list_ = true;
+    observer_list = enabled_state_observer_list_;
+  }
+  // Notify observers outside the lock in case they trigger trace events.
+  for (size_t i = 0; i < observer_list.size(); ++i)
+    observer_list[i]->OnTraceLogEnabled();
+
+  {
+    AutoLock lock(lock_);
+    dispatching_to_observer_list_ = false;
+  }
+}
+
+void TraceLog::SetArgumentFilterPredicate(
+    const ArgumentFilterPredicate& argument_filter_predicate) {
+  AutoLock lock(lock_);
+  DCHECK(!argument_filter_predicate.is_null());
+  DCHECK(argument_filter_predicate_.is_null());
+  argument_filter_predicate_ = argument_filter_predicate;
+}
+
+TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceConfig(
+    const TraceConfig& config) {
+  InternalTraceOptions ret =
+      config.IsSamplingEnabled() ? kInternalEnableSampling : kInternalNone;
+  if (config.IsArgumentFilterEnabled())
+    ret |= kInternalEnableArgumentFilter;
+  switch (config.GetTraceRecordMode()) {
+    case RECORD_UNTIL_FULL:
+      return ret | kInternalRecordUntilFull;
+    case RECORD_CONTINUOUSLY:
+      return ret | kInternalRecordContinuously;
+    case ECHO_TO_CONSOLE:
+      return ret | kInternalEchoToConsole;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      return ret | kInternalRecordAsMuchAsPossible;
+  }
+  NOTREACHED();
+  return kInternalNone;
+}
+
+TraceConfig TraceLog::GetCurrentTraceConfig() const {
+  AutoLock lock(lock_);
+  return trace_config_;
+}
+
+void TraceLog::SetDisabled() {
+  AutoLock lock(lock_);
+  SetDisabledWhileLocked();
+}
+
+void TraceLog::SetDisabledWhileLocked() {
+  lock_.AssertAcquired();
+
+  if (!IsEnabled())
+    return;
+
+  if (dispatching_to_observer_list_) {
+    DLOG(ERROR)
+        << "Cannot manipulate TraceLog::Enabled state from an observer.";
+    return;
+  }
+
+  mode_ = DISABLED;
+
+  if (sampling_thread_.get()) {
+    // Stop the sampling thread.
+    sampling_thread_->Stop();
+    lock_.Release();
+    PlatformThread::Join(sampling_thread_handle_);
+    lock_.Acquire();
+    sampling_thread_handle_ = PlatformThreadHandle();
+    sampling_thread_.reset();
+  }
+
+  trace_config_.Clear();
+  subtle::NoBarrier_Store(&watch_category_, 0);
+  watch_event_name_ = "";
+  UpdateCategoryGroupEnabledFlags();
+  AddMetadataEventsWhileLocked();
+
+  // Remove metadata events so they will not get added to a subsequent trace.
+  metadata_events_.clear();
+
+  dispatching_to_observer_list_ = true;
+  std::vector<EnabledStateObserver*> observer_list =
+      enabled_state_observer_list_;
+
+  {
+    // 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) {
+  AutoLock lock(lock_);
+  enabled_state_observer_list_.push_back(listener);
+}
+
+void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
+  AutoLock lock(lock_);
+  std::vector<EnabledStateObserver*>::iterator it =
+      std::find(enabled_state_observer_list_.begin(),
+                enabled_state_observer_list_.end(), listener);
+  if (it != enabled_state_observer_list_.end())
+    enabled_state_observer_list_.erase(it);
+}
+
+bool TraceLog::HasEnabledStateObserver(EnabledStateObserver* listener) const {
+  AutoLock lock(lock_);
+  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();
+}
+
+TraceEvent* TraceLog::AddEventToThreadSharedChunkWhileLocked(
+    TraceEventHandle* handle,
+    bool check_buffer_is_full) {
+  lock_.AssertAcquired();
+
+  if (thread_shared_chunk_ && thread_shared_chunk_->IsFull()) {
+    logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                std::move(thread_shared_chunk_));
+  }
+
+  if (!thread_shared_chunk_) {
+    thread_shared_chunk_ =
+        logged_events_->GetChunk(&thread_shared_chunk_index_);
+    if (check_buffer_is_full)
+      CheckIfBufferIsFullWhileLocked();
+  }
+  if (!thread_shared_chunk_)
+    return NULL;
+
+  size_t event_index;
+  TraceEvent* trace_event = thread_shared_chunk_->AddTraceEvent(&event_index);
+  if (trace_event && handle) {
+    MakeHandle(thread_shared_chunk_->seq(), thread_shared_chunk_index_,
+               event_index, handle);
+  }
+  return trace_event;
+}
+
+void TraceLog::CheckIfBufferIsFullWhileLocked() {
+  lock_.AssertAcquired();
+  if (logged_events_->IsFull()) {
+    if (buffer_limit_reached_timestamp_.is_null()) {
+      buffer_limit_reached_timestamp_ = OffsetNow();
+    }
+    SetDisabledWhileLocked();
+  }
+}
+
+void TraceLog::SetEventCallbackEnabled(const TraceConfig& trace_config,
+                                       EventCallback cb) {
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&event_callback_,
+                          reinterpret_cast<subtle::AtomicWord>(cb));
+  event_callback_trace_config_ = trace_config;
+  UpdateCategoryGroupEnabledFlags();
+};
+
+void TraceLog::SetEventCallbackDisabled() {
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&event_callback_, 0);
+  UpdateCategoryGroupEnabledFlags();
+}
+
+// Flush() works as the following:
+// 1. Flush() is called in thread A whose task runner is saved in
+//    flush_task_runner_;
+// 2. If thread_message_loops_ is not empty, thread A posts task to each message
+//    loop to flush the thread local buffers; otherwise finish the flush;
+// 3. FlushCurrentThread() deletes the thread local event buffer:
+//    - The last batch of events of the thread are flushed into the main buffer;
+//    - The message loop will be removed from thread_message_loops_;
+//    If this is the last message loop, finish the flush;
+// 4. If any thread hasn't finish its flush in time, finish the flush.
+void TraceLog::Flush(const TraceLog::OutputCallback& cb,
+                     bool use_worker_thread) {
+  FlushInternal(cb, use_worker_thread, false);
+}
+
+void TraceLog::CancelTracing(const OutputCallback& cb) {
+  SetDisabled();
+  FlushInternal(cb, false, true);
+}
+
+void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb,
+                             bool use_worker_thread,
+                             bool discard_events) {
+  use_worker_thread_ = use_worker_thread;
+  if (IsEnabled()) {
+    // Can't flush when tracing is enabled because otherwise PostTask would
+    // - generate more trace events;
+    // - deschedule the calling thread on some platforms causing inaccurate
+    //   timing of the trace events.
+    scoped_refptr<RefCountedString> empty_result = new RefCountedString;
+    if (!cb.is_null())
+      cb.Run(empty_result, false);
+    LOG(WARNING) << "Ignored TraceLog::Flush called when tracing is enabled";
+    return;
+  }
+
+  int generation = this->generation();
+  // Copy of thread_message_loops_ to be used without locking.
+  std::vector<scoped_refptr<SingleThreadTaskRunner>>
+      thread_message_loop_task_runners;
+  {
+    AutoLock lock(lock_);
+    DCHECK(!flush_task_runner_);
+    flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
+                             ? ThreadTaskRunnerHandle::Get()
+                             : nullptr;
+    DCHECK(!thread_message_loops_.size() || flush_task_runner_);
+    flush_output_callback_ = cb;
+
+    if (thread_shared_chunk_) {
+      logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                  std::move(thread_shared_chunk_));
+    }
+
+    if (thread_message_loops_.size()) {
+      for (hash_set<MessageLoop*>::const_iterator it =
+               thread_message_loops_.begin();
+           it != thread_message_loops_.end(); ++it) {
+        thread_message_loop_task_runners.push_back((*it)->task_runner());
+      }
+    }
+  }
+
+  if (thread_message_loop_task_runners.size()) {
+    for (size_t i = 0; i < thread_message_loop_task_runners.size(); ++i) {
+      thread_message_loop_task_runners[i]->PostTask(
+          FROM_HERE, Bind(&TraceLog::FlushCurrentThread, Unretained(this),
+                          generation, discard_events));
+    }
+    flush_task_runner_->PostDelayedTask(
+        FROM_HERE, Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation,
+                        discard_events),
+        TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
+    return;
+  }
+
+  FinishFlush(generation, discard_events);
+}
+
+// Usually it runs on a different thread.
+void TraceLog::ConvertTraceEventsToTraceFormat(
+    scoped_ptr<TraceBuffer> logged_events,
+    const OutputCallback& flush_output_callback,
+    const ArgumentFilterPredicate& argument_filter_predicate) {
+  if (flush_output_callback.is_null())
+    return;
+
+  // The callback need to be called at least once even if there is no events
+  // to let the caller know the completion of flush.
+  scoped_refptr<RefCountedString> json_events_str_ptr = new RefCountedString();
+  while (const TraceBufferChunk* chunk = logged_events->NextChunk()) {
+    for (size_t j = 0; j < chunk->size(); ++j) {
+      size_t size = json_events_str_ptr->size();
+      if (size > kTraceEventBufferSizeInBytes) {
+        flush_output_callback.Run(json_events_str_ptr, true);
+        json_events_str_ptr = new RefCountedString();
+      } else if (size) {
+        json_events_str_ptr->data().append(",\n");
+      }
+      chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()),
+                                         argument_filter_predicate);
+    }
+  }
+  flush_output_callback.Run(json_events_str_ptr, false);
+}
+
+void TraceLog::FinishFlush(int generation, bool discard_events) {
+  scoped_ptr<TraceBuffer> previous_logged_events;
+  OutputCallback flush_output_callback;
+  ArgumentFilterPredicate argument_filter_predicate;
+
+  if (!CheckGeneration(generation))
+    return;
+
+  {
+    AutoLock lock(lock_);
+
+    previous_logged_events.swap(logged_events_);
+    UseNextTraceBuffer();
+    thread_message_loops_.clear();
+
+    flush_task_runner_ = NULL;
+    flush_output_callback = flush_output_callback_;
+    flush_output_callback_.Reset();
+
+    if (trace_options() & kInternalEnableArgumentFilter) {
+      CHECK(!argument_filter_predicate_.is_null());
+      argument_filter_predicate = argument_filter_predicate_;
+    }
+  }
+
+  if (discard_events) {
+    if (!flush_output_callback.is_null()) {
+      scoped_refptr<RefCountedString> empty_result = new RefCountedString;
+      flush_output_callback.Run(empty_result, false);
+    }
+    return;
+  }
+
+  if (use_worker_thread_ &&
+      WorkerPool::PostTask(
+          FROM_HERE, Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
+                          Passed(&previous_logged_events),
+                          flush_output_callback, argument_filter_predicate),
+          true)) {
+    return;
+  }
+
+  ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
+                                  flush_output_callback,
+                                  argument_filter_predicate);
+}
+
+// Run in each thread holding a local event buffer.
+void TraceLog::FlushCurrentThread(int generation, bool discard_events) {
+  {
+    AutoLock lock(lock_);
+    if (!CheckGeneration(generation) || !flush_task_runner_) {
+      // This is late. The corresponding flush has finished.
+      return;
+    }
+  }
+
+  // This will flush the thread local buffer.
+  delete thread_local_event_buffer_.Get();
+
+  AutoLock lock(lock_);
+  if (!CheckGeneration(generation) || !flush_task_runner_ ||
+      thread_message_loops_.size())
+    return;
+
+  flush_task_runner_->PostTask(
+      FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation,
+                      discard_events));
+}
+
+void TraceLog::OnFlushTimeout(int generation, bool discard_events) {
+  {
+    AutoLock lock(lock_);
+    if (!CheckGeneration(generation) || !flush_task_runner_) {
+      // Flush has finished before timeout.
+      return;
+    }
+
+    LOG(WARNING)
+        << "The following threads haven't finished flush in time. "
+           "If this happens stably for some thread, please call "
+           "TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop() from "
+           "the thread to avoid its trace events from being lost.";
+    for (hash_set<MessageLoop*>::const_iterator it =
+             thread_message_loops_.begin();
+         it != thread_message_loops_.end(); ++it) {
+      LOG(WARNING) << "Thread: " << (*it)->thread_name();
+    }
+  }
+  FinishFlush(generation, discard_events);
+}
+
+void TraceLog::FlushButLeaveBufferIntact(
+    const TraceLog::OutputCallback& flush_output_callback) {
+  scoped_ptr<TraceBuffer> previous_logged_events;
+  ArgumentFilterPredicate argument_filter_predicate;
+  {
+    AutoLock lock(lock_);
+    AddMetadataEventsWhileLocked();
+    if (thread_shared_chunk_) {
+      // Return the chunk to the main buffer to flush the sampling data.
+      logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                  std::move(thread_shared_chunk_));
+    }
+    previous_logged_events = logged_events_->CloneForIteration();
+
+    if (trace_options() & kInternalEnableArgumentFilter) {
+      CHECK(!argument_filter_predicate_.is_null());
+      argument_filter_predicate = argument_filter_predicate_;
+    }
+  }  // release lock
+
+  ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
+                                  flush_output_callback,
+                                  argument_filter_predicate);
+}
+
+void TraceLog::UseNextTraceBuffer() {
+  logged_events_.reset(CreateTraceBuffer());
+  subtle::NoBarrier_AtomicIncrement(&generation_, 1);
+  thread_shared_chunk_.reset();
+  thread_shared_chunk_index_ = 0;
+}
+
+TraceEventHandle TraceLog::AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase,
+      category_group_enabled,
+      name,
+      id,
+      trace_event_internal::kNoId,  // context_id
+      trace_event_internal::kNoId,  // bind_id
+      thread_id,
+      now,
+      num_args,
+      arg_names,
+      arg_types,
+      arg_values,
+      convertable_values,
+      flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithContextId(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    unsigned long long context_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 int flags) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase,
+      category_group_enabled,
+      name,
+      id,
+      context_id,
+      trace_event_internal::kNoId,  // bind_id
+      thread_id,
+      now,
+      num_args,
+      arg_names,
+      arg_types,
+      arg_values,
+      convertable_values,
+      flags | TRACE_EVENT_FLAG_HAS_CONTEXT_ID);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithProcessId(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int process_id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase,
+      category_group_enabled,
+      name,
+      id,
+      trace_event_internal::kNoId,  // context_id
+      trace_event_internal::kNoId,  // bind_id
+      process_id,
+      now,
+      num_args,
+      arg_names,
+      arg_types,
+      arg_values,
+      convertable_values,
+      flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID);
+}
+
+// Handle legacy calls to AddTraceEventWithThreadIdAndTimestamp
+// with kNoId as bind_id
+TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    unsigned long long context_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 int flags) {
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase,
+      category_group_enabled,
+      name,
+      id,
+      context_id,
+      trace_event_internal::kNoId,  // bind_id
+      thread_id,
+      timestamp,
+      num_args,
+      arg_names,
+      arg_types,
+      arg_values,
+      convertable_values,
+      flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    unsigned long long context_id,
+    unsigned long long bind_id,
+    int thread_id,
+    const TimeTicks& timestamp,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  TraceEventHandle handle = {0, 0, 0};
+  if (!*category_group_enabled)
+    return handle;
+
+  // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
+  // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
+  // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
+  if (thread_is_in_trace_event_.Get())
+    return handle;
+
+  AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
+
+  DCHECK(name);
+  DCHECK(!timestamp.is_null());
+
+  if (flags & TRACE_EVENT_FLAG_MANGLE_ID) {
+    if ((flags & TRACE_EVENT_FLAG_FLOW_IN) ||
+        (flags & TRACE_EVENT_FLAG_FLOW_OUT))
+      bind_id = MangleEventId(bind_id);
+    id = MangleEventId(id);
+  }
+
+  TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
+  ThreadTicks thread_now = ThreadNow();
+
+  // |thread_local_event_buffer_| can be null if the current thread doesn't have
+  // a message loop or the message loop is blocked.
+  InitializeThreadLocalEventBufferIfSupported();
+  auto thread_local_event_buffer = thread_local_event_buffer_.Get();
+
+  // Check and update the current thread name only if the event is for the
+  // current thread to avoid locks in most cases.
+  if (thread_id == static_cast<int>(PlatformThread::CurrentId())) {
+    const char* new_name =
+        ThreadIdNameManager::GetInstance()->GetName(thread_id);
+    // Check if the thread name has been set or changed since the previous
+    // call (if any), but don't bother if the new name is empty. Note this will
+    // not detect a thread name change within the same char* buffer address: we
+    // favor common case performance over corner case correctness.
+    if (new_name != g_current_thread_name.Get().Get() && new_name &&
+        *new_name) {
+      g_current_thread_name.Get().Set(new_name);
+
+      AutoLock thread_info_lock(thread_info_lock_);
+
+      hash_map<int, std::string>::iterator existing_name =
+          thread_names_.find(thread_id);
+      if (existing_name == thread_names_.end()) {
+        // This is a new thread id, and a new name.
+        thread_names_[thread_id] = new_name;
+      } else {
+        // This is a thread id that we've seen before, but potentially with a
+        // new name.
+        std::vector<StringPiece> existing_names = base::SplitStringPiece(
+            existing_name->second, ",", base::KEEP_WHITESPACE,
+            base::SPLIT_WANT_NONEMPTY);
+        bool found = std::find(existing_names.begin(), existing_names.end(),
+                               new_name) != existing_names.end();
+        if (!found) {
+          if (existing_names.size())
+            existing_name->second.push_back(',');
+          existing_name->second.append(new_name);
+        }
+      }
+    }
+  }
+
+#if defined(OS_WIN)
+  // This is done sooner rather than later, to avoid creating the event and
+  // acquiring the lock, which is not needed for ETW as it's already threadsafe.
+  if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
+    TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
+                                  num_args, arg_names, arg_types, arg_values,
+                                  convertable_values);
+#endif  // OS_WIN
+
+  std::string console_message;
+  if (*category_group_enabled &
+      (ENABLED_FOR_RECORDING | 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,
+                              context_id,
+                              bind_id,
+                              num_args,
+                              arg_names,
+                              arg_types,
+                              arg_values,
+                              convertable_values,
+                              flags);
+
+#if defined(OS_ANDROID)
+      trace_event->SendToATrace();
+#endif
+    }
+
+    if (trace_options() & kInternalEchoToConsole) {
+      console_message = EventToConsoleMessage(
+          phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
+          timestamp, trace_event);
+    }
+  }
+
+  if (console_message.size())
+    LOG(ERROR) << console_message;
+
+  if (reinterpret_cast<const unsigned char*>(
+          subtle::NoBarrier_Load(&watch_category_)) == category_group_enabled) {
+    bool event_name_matches;
+    WatchEventCallback watch_event_callback_copy;
+    {
+      AutoLock lock(lock_);
+      event_name_matches = watch_event_name_ == name;
+      watch_event_callback_copy = watch_event_callback_;
+    }
+    if (event_name_matches) {
+      if (!watch_event_callback_copy.is_null())
+        watch_event_callback_copy.Run();
+    }
+  }
+
+  if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
+    EventCallback event_callback = reinterpret_cast<EventCallback>(
+        subtle::NoBarrier_Load(&event_callback_));
+    if (event_callback) {
+      event_callback(
+          offset_event_timestamp,
+          phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
+          category_group_enabled, name, id, num_args, arg_names, arg_types,
+          arg_values, flags);
+    }
+  }
+
+  if (base::trace_event::AllocationContextTracker::capture_enabled()) {
+    if (phase == TRACE_EVENT_PHASE_BEGIN || phase == TRACE_EVENT_PHASE_COMPLETE)
+      base::trace_event::AllocationContextTracker::PushPseudoStackFrame(name);
+    else if (phase == TRACE_EVENT_PHASE_END)
+      // The pop for |TRACE_EVENT_PHASE_COMPLETE| events
+      // is in |TraceLog::UpdateTraceEventDuration|.
+      base::trace_event::AllocationContextTracker::PopPseudoStackFrame(name);
+  }
+
+  return handle;
+}
+
+void TraceLog::AddMetadataEvent(
+    const char* name,
+    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 int flags) {
+  scoped_ptr<TraceEvent> trace_event(new TraceEvent);
+  trace_event->Initialize(
+      0,  // thread_id
+      TimeTicks(), ThreadTicks(), TRACE_EVENT_PHASE_METADATA,
+      &g_category_group_enabled[g_category_metadata], name,
+      trace_event_internal::kNoId,  // id
+      trace_event_internal::kNoId,  // context_id
+      trace_event_internal::kNoId,  // bind_id
+      num_args, arg_names, arg_types, arg_values, convertable_values, flags);
+  AutoLock lock(lock_);
+  metadata_events_.push_back(std::move(trace_event));
+}
+
+// May be called when a COMPELETE event ends and the unfinished event has been
+// recycled (phase == TRACE_EVENT_PHASE_END and trace_event == NULL).
+std::string TraceLog::EventToConsoleMessage(unsigned char phase,
+                                            const TimeTicks& timestamp,
+                                            TraceEvent* trace_event) {
+  AutoLock thread_info_lock(thread_info_lock_);
+
+  // The caller should translate TRACE_EVENT_PHASE_COMPLETE to
+  // TRACE_EVENT_PHASE_BEGIN or TRACE_EVENT_END.
+  DCHECK(phase != TRACE_EVENT_PHASE_COMPLETE);
+
+  TimeDelta duration;
+  int thread_id =
+      trace_event ? trace_event->thread_id() : PlatformThread::CurrentId();
+  if (phase == TRACE_EVENT_PHASE_END) {
+    duration = timestamp - thread_event_start_times_[thread_id].top();
+    thread_event_start_times_[thread_id].pop();
+  }
+
+  std::string thread_name = thread_names_[thread_id];
+  if (thread_colors_.find(thread_name) == thread_colors_.end())
+    thread_colors_[thread_name] = (thread_colors_.size() % 6) + 1;
+
+  std::ostringstream log;
+  log << base::StringPrintf("%s: \x1b[0;3%dm", thread_name.c_str(),
+                            thread_colors_[thread_name]);
+
+  size_t depth = 0;
+  if (thread_event_start_times_.find(thread_id) !=
+      thread_event_start_times_.end())
+    depth = thread_event_start_times_[thread_id].size();
+
+  for (size_t i = 0; i < depth; ++i)
+    log << "| ";
+
+  if (trace_event)
+    trace_event->AppendPrettyPrinted(&log);
+  if (phase == TRACE_EVENT_PHASE_END)
+    log << base::StringPrintf(" (%.3f ms)", duration.InMillisecondsF());
+
+  log << "\x1b[0;m";
+
+  if (phase == TRACE_EVENT_PHASE_BEGIN)
+    thread_event_start_times_[thread_id].push(timestamp);
+
+  return log.str();
+}
+
+void TraceLog::UpdateTraceEventDuration(
+    const unsigned char* category_group_enabled,
+    const char* name,
+    TraceEventHandle handle) {
+  char category_group_enabled_local = *category_group_enabled;
+  if (!category_group_enabled_local)
+    return;
+
+  // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
+  // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
+  // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
+  if (thread_is_in_trace_event_.Get())
+    return;
+
+  AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
+
+  ThreadTicks thread_now = ThreadNow();
+  TimeTicks now = OffsetNow();
+
+#if defined(OS_WIN)
+  // Generate an ETW event that marks the end of a complete event.
+  if (category_group_enabled_local & ENABLED_FOR_ETW_EXPORT)
+    TraceEventETWExport::AddCompleteEndEvent(name);
+#endif  // OS_WIN
+
+  std::string console_message;
+  if (category_group_enabled_local & ENABLED_FOR_RECORDING) {
+    OptionalAutoLock lock(&lock_);
+
+    TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
+    if (trace_event) {
+      DCHECK(trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE);
+      trace_event->UpdateDuration(now, thread_now);
+#if defined(OS_ANDROID)
+      trace_event->SendToATrace();
+#endif
+    }
+
+    if (trace_options() & kInternalEchoToConsole) {
+      console_message =
+          EventToConsoleMessage(TRACE_EVENT_PHASE_END, now, trace_event);
+    }
+
+    if (base::trace_event::AllocationContextTracker::capture_enabled()) {
+      // The corresponding push is in |AddTraceEventWithThreadIdAndTimestamp|.
+      base::trace_event::AllocationContextTracker::PopPseudoStackFrame(name);
+    }
+  }
+
+  if (console_message.size())
+    LOG(ERROR) << console_message;
+
+  if (category_group_enabled_local & ENABLED_FOR_EVENT_CALLBACK) {
+    EventCallback event_callback = reinterpret_cast<EventCallback>(
+        subtle::NoBarrier_Load(&event_callback_));
+    if (event_callback) {
+      event_callback(now, TRACE_EVENT_PHASE_END, category_group_enabled, name,
+                     trace_event_internal::kNoId, 0,
+                     nullptr, nullptr, nullptr, TRACE_EVENT_FLAG_NONE);
+    }
+  }
+}
+
+void TraceLog::SetWatchEvent(const std::string& category_name,
+                             const std::string& event_name,
+                             const WatchEventCallback& callback) {
+  const unsigned char* category =
+      GetCategoryGroupEnabled(category_name.c_str());
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&watch_category_,
+                          reinterpret_cast<subtle::AtomicWord>(category));
+  watch_event_name_ = event_name;
+  watch_event_callback_ = callback;
+}
+
+void TraceLog::CancelWatchEvent() {
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&watch_category_, 0);
+  watch_event_name_ = "";
+  watch_event_callback_.Reset();
+}
+
+uint64 TraceLog::MangleEventId(uint64 id) {
+  return id ^ process_id_hash_;
+}
+
+void TraceLog::AddMetadataEventsWhileLocked() {
+  lock_.AssertAcquired();
+
+  // Copy metadata added by |AddMetadataEvent| into the trace log.
+  for (const scoped_ptr<TraceEvent>& event : metadata_events_)
+    AddEventToThreadSharedChunkWhileLocked(nullptr, false)->CopyFrom(*event);
+
+#if !defined(OS_NACL)  // NaCl shouldn't expose the process id.
+  InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                          0, "num_cpus", "number",
+                          base::SysInfo::NumberOfProcessors());
+#endif
+
+  int current_thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  if (process_sort_index_ != 0) {
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id, "process_sort_index",
+                            "sort_index", process_sort_index_);
+  }
+
+  if (process_name_.size()) {
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id, "process_name", "name",
+                            process_name_);
+  }
+
+  if (process_labels_.size() > 0) {
+    std::vector<std::string> labels;
+    for (base::hash_map<int, std::string>::iterator it =
+             process_labels_.begin();
+         it != process_labels_.end(); it++) {
+      labels.push_back(it->second);
+    }
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id, "process_labels", "labels",
+                            base::JoinString(labels, ","));
+  }
+
+  // Thread sort indices.
+  for (hash_map<int, int>::iterator it = thread_sort_indices_.begin();
+       it != thread_sort_indices_.end(); it++) {
+    if (it->second == 0)
+      continue;
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            it->first, "thread_sort_index", "sort_index",
+                            it->second);
+  }
+
+  // Thread names.
+  AutoLock thread_info_lock(thread_info_lock_);
+  for (hash_map<int, std::string>::iterator it = thread_names_.begin();
+       it != thread_names_.end(); it++) {
+    if (it->second.empty())
+      continue;
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            it->first, "thread_name", "name", it->second);
+  }
+
+  // If buffer is full, add a metadata record to report this.
+  if (!buffer_limit_reached_timestamp_.is_null()) {
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id, "trace_buffer_overflowed",
+                            "overflowed_at_ts",
+                            buffer_limit_reached_timestamp_);
+  }
+}
+
+void TraceLog::WaitSamplingEventForTesting() {
+  if (!sampling_thread_)
+    return;
+  sampling_thread_->WaitSamplingEventForTesting();
+}
+
+void TraceLog::DeleteForTesting() {
+  internal::DeleteTraceLogForTesting::Delete();
+}
+
+TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
+  return GetEventByHandleInternal(handle, NULL);
+}
+
+TraceEvent* TraceLog::GetEventByHandleInternal(TraceEventHandle handle,
+                                               OptionalAutoLock* lock) {
+  if (!handle.chunk_seq)
+    return NULL;
+
+  if (thread_local_event_buffer_.Get()) {
+    TraceEvent* trace_event =
+        thread_local_event_buffer_.Get()->GetEventByHandle(handle);
+    if (trace_event)
+      return trace_event;
+  }
+
+  // The event has been out-of-control of the thread local buffer.
+  // Try to get the event from the main buffer with a lock.
+  if (lock)
+    lock->EnsureAcquired();
+
+  if (thread_shared_chunk_ &&
+      handle.chunk_index == thread_shared_chunk_index_) {
+    return handle.chunk_seq == thread_shared_chunk_->seq()
+               ? thread_shared_chunk_->GetEventAt(handle.event_index)
+               : NULL;
+  }
+
+  return logged_events_->GetEventByHandle(handle);
+}
+
+void TraceLog::SetProcessID(int process_id) {
+  process_id_ = process_id;
+  // Create a FNV hash from the process ID for XORing.
+  // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details.
+  unsigned long long offset_basis = 14695981039346656037ull;
+  unsigned long long fnv_prime = 1099511628211ull;
+  unsigned long long pid = static_cast<unsigned long long>(process_id_);
+  process_id_hash_ = (offset_basis ^ pid) * fnv_prime;
+}
+
+void TraceLog::SetProcessSortIndex(int sort_index) {
+  AutoLock lock(lock_);
+  process_sort_index_ = sort_index;
+}
+
+void TraceLog::SetProcessName(const std::string& process_name) {
+  AutoLock lock(lock_);
+  process_name_ = process_name;
+}
+
+void TraceLog::UpdateProcessLabel(int label_id,
+                                  const std::string& current_label) {
+  if (!current_label.length())
+    return RemoveProcessLabel(label_id);
+
+  AutoLock lock(lock_);
+  process_labels_[label_id] = current_label;
+}
+
+void TraceLog::RemoveProcessLabel(int label_id) {
+  AutoLock lock(lock_);
+  base::hash_map<int, std::string>::iterator it =
+      process_labels_.find(label_id);
+  if (it == process_labels_.end())
+    return;
+
+  process_labels_.erase(it);
+}
+
+void TraceLog::SetThreadSortIndex(PlatformThreadId thread_id, int sort_index) {
+  AutoLock lock(lock_);
+  thread_sort_indices_[static_cast<int>(thread_id)] = sort_index;
+}
+
+void TraceLog::SetTimeOffset(TimeDelta offset) {
+  time_offset_ = offset;
+}
+
+size_t TraceLog::GetObserverCountForTest() const {
+  return enabled_state_observer_list_.size();
+}
+
+void TraceLog::SetCurrentThreadBlocksMessageLoop() {
+  thread_blocks_message_loop_.Set(true);
+  if (thread_local_event_buffer_.Get()) {
+    // This will flush the thread local buffer.
+    delete thread_local_event_buffer_.Get();
+  }
+}
+
+TraceBuffer* TraceLog::CreateTraceBuffer() {
+  InternalTraceOptions options = trace_options();
+  if (options & kInternalRecordContinuously)
+    return TraceBuffer::CreateTraceBufferRingBuffer(
+        kTraceEventRingBufferChunks);
+  else if ((options & kInternalEnableSampling) && mode_ == MONITORING_MODE)
+    return TraceBuffer::CreateTraceBufferRingBuffer(
+        kMonitorTraceEventBufferChunks);
+  else if (options & kInternalEchoToConsole)
+    return TraceBuffer::CreateTraceBufferRingBuffer(
+        kEchoToConsoleTraceEventBufferChunks);
+  else if (options & kInternalRecordAsMuchAsPossible)
+    return TraceBuffer::CreateTraceBufferVectorOfSize(
+        kTraceEventVectorBigBufferChunks);
+  return TraceBuffer::CreateTraceBufferVectorOfSize(
+      kTraceEventVectorBufferChunks);
+}
+
+#if defined(OS_WIN)
+void TraceLog::UpdateETWCategoryGroupEnabledFlags() {
+  AutoLock lock(lock_);
+  size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+  // Go through each category and set/clear the ETW bit depending on whether the
+  // category is enabled.
+  for (size_t i = 0; i < category_index; i++) {
+    const char* category_group = g_category_groups[i];
+    DCHECK(category_group);
+    if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
+            category_group)) {
+      g_category_group_enabled[i] |= ENABLED_FOR_ETW_EXPORT;
+    } else {
+      g_category_group_enabled[i] &= ~ENABLED_FOR_ETW_EXPORT;
+    }
+  }
+}
+#endif  // defined(OS_WIN)
+
+void ConvertableToTraceFormat::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("ConvertableToTraceFormat(Unknown)", sizeof(*this));
+}
+
+}  // 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::kNoId,  // id
+            trace_event_internal::kNoId,  // context_id
+            static_cast<int>(base::PlatformThread::CurrentId()),  // thread_id
+            base::TimeTicks::Now(),
+            trace_event_internal::kZeroNumArgs,
+            nullptr,
+            nullptr,
+            nullptr,
+            nullptr,
+            TRACE_EVENT_FLAG_NONE);
+  }
+}
+
+ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() {
+  if (*category_group_enabled_) {
+    TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, name_,
+                                                event_handle_);
+  }
+}
+
+}  // namespace trace_event_internal
diff --git a/base/trace_event/trace_log.h b/base/trace_event/trace_log.h
new file mode 100644
index 0000000..8aa7ff8
--- /dev/null
+++ b/base/trace_event/trace_log.h
@@ -0,0 +1,500 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_LOG_H_
+#define BASE_TRACE_EVENT_TRACE_LOG_H_
+
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+
+template <typename Type>
+struct DefaultSingletonTraits;
+class RefCountedString;
+
+namespace trace_event {
+
+class TraceBuffer;
+class TraceBufferChunk;
+class TraceEvent;
+class TraceEventMemoryOverhead;
+class TraceSamplingThread;
+
+struct BASE_EXPORT TraceLogStatus {
+  TraceLogStatus();
+  ~TraceLogStatus();
+  size_t event_capacity;
+  size_t event_count;
+};
+
+class BASE_EXPORT TraceLog : public MemoryDumpProvider {
+ public:
+  enum Mode {
+    DISABLED = 0,
+    RECORDING_MODE,
+    MONITORING_MODE,
+  };
+
+  // The pointer returned from GetCategoryGroupEnabledInternal() points to a
+  // value with zero or more of the following bits. Used in this class only.
+  // The TRACE_EVENT macros should only use the value as a bool.
+  // These values must be in sync with macro values in TraceEvent.h in Blink.
+  enum CategoryGroupEnabledFlags {
+    // Category group enabled for the recording mode.
+    ENABLED_FOR_RECORDING = 1 << 0,
+    // Category group enabled for the monitoring mode.
+    ENABLED_FOR_MONITORING = 1 << 1,
+    // Category group enabled by SetEventCallbackEnabled().
+    ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
+    // Category group enabled to export events to ETW.
+    ENABLED_FOR_ETW_EXPORT = 1 << 3
+  };
+
+  static TraceLog* GetInstance();
+
+  // Get set of known category groups. This can change as new code paths are
+  // reached. The known category groups are inserted into |category_groups|.
+  void GetKnownCategoryGroups(std::vector<std::string>* category_groups);
+
+  // Retrieves a copy (for thread-safety) of the current TraceConfig.
+  TraceConfig GetCurrentTraceConfig() const;
+
+  // Initializes the thread-local event buffer, if not already initialized and
+  // if the current thread supports that (has a message loop).
+  void InitializeThreadLocalEventBufferIfSupported();
+
+  // Enables normal tracing (recording trace events in the trace buffer).
+  // See TraceConfig comments for details on how to control what categories
+  // will be traced. If tracing has already been enabled, |category_filter| will
+  // be merged into the current category filter.
+  void SetEnabled(const TraceConfig& trace_config, Mode mode);
+
+  // Disables normal tracing for all categories.
+  void SetDisabled();
+
+  bool IsEnabled() { return mode_ != DISABLED; }
+
+  // The number of times we have begun recording traces. If tracing is off,
+  // returns -1. If tracing is on, then it returns the number of times we have
+  // recorded a trace. By watching for this number to increment, you can
+  // passively discover when a new trace has begun. This is then used to
+  // implement the TRACE_EVENT_IS_NEW_TRACE() primitive.
+  int GetNumTracesRecorded();
+
+#if defined(OS_ANDROID)
+  void StartATrace();
+  void StopATrace();
+  void AddClockSyncMetadataEvent();
+#endif
+
+  // Enabled state listeners give a callback when tracing is enabled or
+  // disabled. This can be used to tie into other library's tracing systems
+  // on-demand.
+  class BASE_EXPORT EnabledStateObserver {
+   public:
+    virtual ~EnabledStateObserver() = default;
+
+    // Called just after the tracing system becomes enabled, outside of the
+    // |lock_|. TraceLog::IsEnabled() is true at this point.
+    virtual void OnTraceLogEnabled() = 0;
+
+    // Called just after the tracing system disables, outside of the |lock_|.
+    // TraceLog::IsEnabled() is false at this point.
+    virtual void OnTraceLogDisabled() = 0;
+  };
+  void AddEnabledStateObserver(EnabledStateObserver* listener);
+  void RemoveEnabledStateObserver(EnabledStateObserver* listener);
+  bool HasEnabledStateObserver(EnabledStateObserver* listener) const;
+
+  TraceLogStatus GetStatus() const;
+  bool BufferIsFull() const;
+
+  // Computes an estimate of the size of the TraceLog including all the retained
+  // objects.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+  // Not using base::Callback because of its limited by 7 parameters.
+  // Also, using primitive type allows directly passing callback from WebCore.
+  // WARNING: It is possible for the previously set callback to be called
+  // after a call to SetEventCallbackEnabled() that replaces or a call to
+  // SetEventCallbackDisabled() that disables the callback.
+  // This callback may be invoked on any thread.
+  // For TRACE_EVENT_PHASE_COMPLETE events, the client will still receive pairs
+  // of TRACE_EVENT_PHASE_BEGIN and TRACE_EVENT_PHASE_END events to keep the
+  // interface simple.
+  typedef void (*EventCallback)(TimeTicks timestamp,
+                                char phase,
+                                const unsigned char* category_group_enabled,
+                                const char* name,
+                                unsigned long long id,
+                                int num_args,
+                                const char* const arg_names[],
+                                const unsigned char arg_types[],
+                                const unsigned long long arg_values[],
+                                unsigned int flags);
+
+  // Enable tracing for EventCallback.
+  void SetEventCallbackEnabled(const TraceConfig& trace_config,
+                               EventCallback cb);
+  void SetEventCallbackDisabled();
+  void SetArgumentFilterPredicate(
+      const ArgumentFilterPredicate& argument_filter_predicate);
+
+  // Flush all collected events to the given output callback. The callback will
+  // be called one or more times either synchronously or asynchronously from
+  // the current thread with IPC-bite-size chunks. The string format is
+  // undefined. Use TraceResultBuffer to convert one or more trace strings to
+  // JSON. The callback can be null if the caller doesn't want any data.
+  // Due to the implementation of thread-local buffers, flush can't be
+  // done when tracing is enabled. If called when tracing is enabled, the
+  // callback will be called directly with (empty_string, false) to indicate
+  // the end of this unsuccessful flush. Flush does the serialization
+  // on the same thread if the caller doesn't set use_worker_thread explicitly.
+  typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
+                              bool has_more_events)> OutputCallback;
+  void Flush(const OutputCallback& cb, bool use_worker_thread = false);
+  void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback);
+
+  // Cancels tracing and discards collected data.
+  void CancelTracing(const OutputCallback& cb);
+
+  // Called by TRACE_EVENT* macros, don't call this directly.
+  // The name parameter is a category group for example:
+  // TRACE_EVENT0("renderer,webkit", "WebViewImpl::HandleInputEvent")
+  static const unsigned char* GetCategoryGroupEnabled(const char* name);
+  static const char* GetCategoryGroupName(
+      const unsigned char* category_group_enabled);
+
+  // Called by TRACE_EVENT* macros, don't call this directly.
+  // If |copy| is set, |name|, |arg_name1| and |arg_name2| will be deep copied
+  // into the event; see "Memory scoping note" and TRACE_EVENT_COPY_XXX above.
+  TraceEventHandle AddTraceEvent(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      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 int flags);
+  TraceEventHandle AddTraceEventWithContextId(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      unsigned long long context_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 int flags);
+  TraceEventHandle AddTraceEventWithProcessId(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int process_id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned int flags);
+  TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      unsigned long long context_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 int flags);
+  TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      unsigned long long context_id,
+      unsigned long long bind_id,
+      int thread_id,
+      const TimeTicks& timestamp,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned int flags);
+
+  // Adds a metadata event that will be written when the trace log is flushed.
+  void AddMetadataEvent(
+      const char* name,
+      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 int flags);
+
+  void UpdateTraceEventDuration(const unsigned char* category_group_enabled,
+                                const char* name,
+                                TraceEventHandle handle);
+
+  // For every matching event, the callback will be called.
+  typedef base::Callback<void()> WatchEventCallback;
+  void SetWatchEvent(const std::string& category_name,
+                     const std::string& event_name,
+                     const WatchEventCallback& callback);
+  // Cancel the watch event. If tracing is enabled, this may race with the
+  // watch event notification firing.
+  void CancelWatchEvent();
+
+  int process_id() const { return process_id_; }
+
+  uint64 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 thread_id, int sort_index);
+
+  // Allow setting an offset between the current TimeTicks time and the time
+  // that should be reported.
+  void SetTimeOffset(TimeDelta offset);
+
+  size_t GetObserverCountForTest() const;
+
+  // Call this method if the current thread may block the message loop to
+  // prevent the thread from using the thread-local buffer because the thread
+  // may not handle the flush request in time causing lost of unflushed events.
+  void SetCurrentThreadBlocksMessageLoop();
+
+#if defined(OS_WIN)
+  // This function is called by the ETW exporting module whenever the ETW
+  // keyword (flags) changes. This keyword indicates which categories should be
+  // exported, so whenever it changes, we adjust accordingly.
+  void UpdateETWCategoryGroupEnabledFlags();
+#endif
+
+ private:
+  typedef unsigned int InternalTraceOptions;
+
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferRingBufferGetReturnChunk);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferRingBufferHalfIteration);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferRingBufferFullIteration);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture, TraceBufferVectorReportFull);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           ConvertTraceConfigToInternalOptions);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceRecordAsMuchAsPossibleMode);
+
+  // This allows constructor and destructor to be private and usable only
+  // by the Singleton class.
+  friend struct DefaultSingletonTraits<TraceLog>;
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override;
+
+  // Enable/disable each category group based on the current mode_,
+  // category_filter_, event_callback_ and event_callback_category_filter_.
+  // Enable the category group in the enabled mode if category_filter_ matches
+  // the category group, or event_callback_ is not null and
+  // event_callback_category_filter_ matches the category group.
+  void UpdateCategoryGroupEnabledFlags();
+  void UpdateCategoryGroupEnabledFlag(size_t category_index);
+
+  // Configure synthetic delays based on the values set in the current
+  // trace config.
+  void UpdateSyntheticDelaysFromTraceConfig();
+
+  InternalTraceOptions GetInternalOptionsFromTraceConfig(
+      const TraceConfig& config);
+
+  class ThreadLocalEventBuffer;
+  class OptionalAutoLock;
+
+  TraceLog();
+  ~TraceLog() override;
+  const unsigned char* GetCategoryGroupEnabledInternal(const char* name);
+  void AddMetadataEventsWhileLocked();
+
+  InternalTraceOptions trace_options() const {
+    return static_cast<InternalTraceOptions>(
+        subtle::NoBarrier_Load(&trace_options_));
+  }
+
+  TraceBuffer* trace_buffer() const { return logged_events_.get(); }
+  TraceBuffer* CreateTraceBuffer();
+
+  std::string EventToConsoleMessage(unsigned char phase,
+                                    const TimeTicks& timestamp,
+                                    TraceEvent* trace_event);
+
+  TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
+                                                     bool check_buffer_is_full);
+  void CheckIfBufferIsFullWhileLocked();
+  void SetDisabledWhileLocked();
+
+  TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
+                                       OptionalAutoLock* lock);
+
+  void FlushInternal(const OutputCallback& cb,
+                     bool use_worker_thread,
+                     bool discard_events);
+
+  // |generation| is used in the following callbacks to check if the callback
+  // is called for the flush of the current |logged_events_|.
+  void FlushCurrentThread(int generation, bool discard_events);
+  // Usually it runs on a different thread.
+  static void ConvertTraceEventsToTraceFormat(
+      scoped_ptr<TraceBuffer> logged_events,
+      const TraceLog::OutputCallback& flush_output_callback,
+      const ArgumentFilterPredicate& argument_filter_predicate);
+  void FinishFlush(int generation, bool discard_events);
+  void OnFlushTimeout(int generation, bool discard_events);
+
+  int generation() const {
+    return static_cast<int>(subtle::NoBarrier_Load(&generation_));
+  }
+  bool CheckGeneration(int generation) const {
+    return generation == this->generation();
+  }
+  void UseNextTraceBuffer();
+
+  TimeTicks OffsetNow() const { return OffsetTimestamp(TimeTicks::Now()); }
+  TimeTicks OffsetTimestamp(const TimeTicks& timestamp) const {
+    return timestamp - time_offset_;
+  }
+
+  // Internal representation of trace options since we store the currently used
+  // trace option as an AtomicWord.
+  static const InternalTraceOptions kInternalNone;
+  static const InternalTraceOptions kInternalRecordUntilFull;
+  static const InternalTraceOptions kInternalRecordContinuously;
+  static const InternalTraceOptions kInternalEchoToConsole;
+  static const InternalTraceOptions kInternalEnableSampling;
+  static const InternalTraceOptions kInternalRecordAsMuchAsPossible;
+  static const InternalTraceOptions kInternalEnableArgumentFilter;
+
+  // This lock protects TraceLog member accesses (except for members protected
+  // by thread_info_lock_) from arbitrary threads.
+  mutable Lock lock_;
+  // This lock protects accesses to thread_names_, thread_event_start_times_
+  // and thread_colors_.
+  Lock thread_info_lock_;
+  Mode mode_;
+  int num_traces_recorded_;
+  scoped_ptr<TraceBuffer> logged_events_;
+  std::vector<scoped_ptr<TraceEvent>> metadata_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_;
+
+  TraceConfig trace_config_;
+  TraceConfig event_callback_trace_config_;
+
+  ThreadLocalPointer<ThreadLocalEventBuffer> thread_local_event_buffer_;
+  ThreadLocalBoolean thread_blocks_message_loop_;
+  ThreadLocalBoolean thread_is_in_trace_event_;
+
+  // Contains the message loops of threads that have had at least one event
+  // added into the local event buffer. Not using SingleThreadTaskRunner
+  // because we need to know the life time of the message loops.
+  hash_set<MessageLoop*> thread_message_loops_;
+
+  // For events which can't be added into the thread local buffer, e.g. events
+  // from threads without a message loop.
+  scoped_ptr<TraceBufferChunk> thread_shared_chunk_;
+  size_t thread_shared_chunk_index_;
+
+  // Set when asynchronous Flush is in progress.
+  OutputCallback flush_output_callback_;
+  scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
+  ArgumentFilterPredicate argument_filter_predicate_;
+  subtle::AtomicWord generation_;
+  bool use_worker_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceLog);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_LOG_H_
diff --git a/base/trace_event/trace_event_impl_constants.cc b/base/trace_event/trace_log_constants.cc
similarity index 81%
rename from base/trace_event/trace_event_impl_constants.cc
rename to base/trace_event/trace_log_constants.cc
index ffeacff..cd2ff0d 100644
--- a/base/trace_event/trace_event_impl_constants.cc
+++ b/base/trace_event/trace_log_constants.cc
@@ -2,14 +2,11 @@
 // 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 "base/trace_event/trace_log.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;
@@ -23,6 +20,8 @@
     TraceLog::kInternalEchoToConsole = 1 << 3;
 const TraceLog::InternalTraceOptions
     TraceLog::kInternalRecordAsMuchAsPossible = 1 << 4;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalEnableArgumentFilter = 1 << 5;
 
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/trace_sampling_thread.cc b/base/trace_event/trace_sampling_thread.cc
new file mode 100644
index 0000000..32ce7bd
--- /dev/null
+++ b/base/trace_event/trace_sampling_thread.cc
@@ -0,0 +1,101 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_sampling_thread.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_log.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceBucketData {
+ public:
+  TraceBucketData(base::subtle::AtomicWord* bucket,
+                  const char* name,
+                  TraceSampleCallback callback);
+  ~TraceBucketData();
+
+  TRACE_EVENT_API_ATOMIC_WORD* bucket;
+  const char* bucket_name;
+  TraceSampleCallback callback;
+};
+
+TraceSamplingThread::TraceSamplingThread()
+    : thread_running_(false), waitable_event_for_testing_(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() {}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_sampling_thread.h b/base/trace_event/trace_sampling_thread.h
new file mode 100644
index 0000000..f976a80
--- /dev/null
+++ b/base/trace_event/trace_sampling_thread.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
+#define BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
+
+#include "base/synchronization/cancellation_flag.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceBucketData;
+typedef base::Callback<void(TraceBucketData*)> TraceSampleCallback;
+
+// This object must be created on the IO thread.
+class TraceSamplingThread : public PlatformThread::Delegate {
+ public:
+  TraceSamplingThread();
+  ~TraceSamplingThread() override;
+
+  // Implementation of PlatformThread::Delegate:
+  void ThreadMain() override;
+
+  static void DefaultSamplingCallback(TraceBucketData* bucket_data);
+
+  void Stop();
+  void WaitSamplingEventForTesting();
+
+ private:
+  friend class TraceLog;
+
+  void GetSamples();
+  // Not thread-safe. Once the ThreadMain has been called, this can no longer
+  // be called.
+  void RegisterSampleBucket(TRACE_EVENT_API_ATOMIC_WORD* bucket,
+                            const char* const name,
+                            TraceSampleCallback callback);
+  // Splits a combined "category\0name" into the two component parts.
+  static void ExtractCategoryAndName(const char* combined,
+                                     const char** category,
+                                     const char** name);
+  std::vector<TraceBucketData> sample_buckets_;
+  bool thread_running_;
+  CancellationFlag cancellation_flag_;
+  WaitableEvent waitable_event_for_testing_;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
diff --git a/base/trace_event/winheap_dump_provider_win.cc b/base/trace_event/winheap_dump_provider_win.cc
index e1e9bcf..7d003c9 100644
--- a/base/trace_event/winheap_dump_provider_win.cc
+++ b/base/trace_event/winheap_dump_provider_win.cc
@@ -6,29 +6,38 @@
 
 #include <windows.h>
 
+#include "base/debug/profiler.h"
+#include "base/strings/string_util.h"
 #include "base/trace_event/process_memory_dump.h"
+#include "base/win/windows_version.h"
 
 namespace base {
 namespace trace_event {
 
+#define DUMP_ROOT_NAME "winheap"
+// static
+const char WinHeapDumpProvider::kAllocatedObjects[] =
+    DUMP_ROOT_NAME "/allocated_objects";
+
 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;
+void ReportHeapDump(ProcessMemoryDump* pmd, const WinHeapInfo& heap_info) {
+  MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump(DUMP_ROOT_NAME);
+  outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes,
+                        heap_info.committed_size);
+
+  MemoryAllocatorDump* inner_dump =
+      pmd->CreateAllocatorDump(WinHeapDumpProvider::kAllocatedObjects);
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes,
+                        heap_info.allocated_size);
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameObjectCount,
+                        MemoryAllocatorDump::kUnitsObjects,
+                        heap_info.block_count);
 }
 
 }  // namespace
@@ -38,7 +47,30 @@
                    LeakySingletonTraits<WinHeapDumpProvider>>::get();
 }
 
-bool WinHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+bool WinHeapDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
+                                       ProcessMemoryDump* pmd) {
+  // This method might be flaky for 2 reasons:
+  //   - GetProcessHeaps is racy by design. It returns a snapshot of the
+  //     available heaps, but there's no guarantee that that snapshot remains
+  //     valid. If a heap disappears between GetProcessHeaps() and HeapWalk()
+  //     then chaos should be assumed. This flakyness is acceptable for tracing.
+  //   - The MSDN page for HeapLock says: "If the HeapLock function is called on
+  //     a heap created with the HEAP_NO_SERIALIZATION flag, the results are
+  //     undefined.". This is a problem on Windows XP where some system DLLs are
+  //     known for creating heaps with this particular flag. For this reason
+  //     this function should be disabled on XP.
+  //
+  // See https://crbug.com/487291 for more details about this.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return false;
+
+  // Disable this dump provider for the SyzyASan instrumented build
+  // because they don't support the heap walking functions yet.
+#if defined(SYZYASAN)
+  if (base::debug::IsBinaryInstrumented())
+    return false;
+#endif
+
   // Retrieves the number of heaps in the current process.
   DWORD number_of_heaps = ::GetProcessHeaps(0, NULL);
   WinHeapInfo all_heap_info = {0};
@@ -68,9 +100,7 @@
     all_heap_info.block_count += heap_info.block_count;
   }
   // Report the heap dump.
-  if (!ReportHeapDump(pmd, all_heap_info, "winheap"))
-    return false;
-
+  ReportHeapDump(pmd, all_heap_info);
   return true;
 }
 
diff --git a/base/trace_event/winheap_dump_provider_win.h b/base/trace_event/winheap_dump_provider_win.h
index 99239a0..e365355 100644
--- a/base/trace_event/winheap_dump_provider_win.h
+++ b/base/trace_event/winheap_dump_provider_win.h
@@ -26,10 +26,15 @@
 // about them.
 class BASE_EXPORT WinHeapDumpProvider : public MemoryDumpProvider {
  public:
+  // Name of the allocated_objects dump. Use this to declare suballocator dumps
+  // from other dump providers.
+  static const char kAllocatedObjects[];
+
   static WinHeapDumpProvider* GetInstance();
 
   // MemoryDumpProvider implementation.
-  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override;
 
  private:
   friend struct DefaultSingletonTraits<WinHeapDumpProvider>;
diff --git a/base/trace_event/winheap_dump_provider_win_unittest.cc b/base/trace_event/winheap_dump_provider_win_unittest.cc
index 2309802..c74a7b7 100644
--- a/base/trace_event/winheap_dump_provider_win_unittest.cc
+++ b/base/trace_event/winheap_dump_provider_win_unittest.cc
@@ -14,13 +14,14 @@
 namespace trace_event {
 
 TEST(WinHeapDumpProviderTest, OnMemoryDump) {
-  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+  ProcessMemoryDump pmd(new MemoryDumpSessionState(nullptr, nullptr));
+  MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
 
   WinHeapDumpProvider* winheap_dump_provider =
       WinHeapDumpProvider::GetInstance();
   ASSERT_NE(static_cast<WinHeapDumpProvider*>(nullptr), winheap_dump_provider);
 
-  ASSERT_TRUE(winheap_dump_provider->OnMemoryDump(&pmd));
+  ASSERT_NO_FATAL_FAILURE(winheap_dump_provider->OnMemoryDump(dump_args, &pmd));
 }
 
 }  // namespace trace_event
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 9db05c0..c7a6a3f 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -310,7 +310,7 @@
     ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER;
 
 // static
-ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
+base::subtle::Atomic32 ThreadData::status_ = ThreadData::UNINITIALIZED;
 
 ThreadData::ThreadData(const std::string& suggested_name)
     : next_(NULL),
@@ -692,7 +692,7 @@
 }
 
 void ThreadData::Initialize() {
-  if (status_ >= DEACTIVATED)
+  if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED)
     return;  // Someone else did the initialization.
   // Due to racy lazy initialization in tests, we'll need to recheck status_
   // after we acquire the lock.
@@ -701,7 +701,7 @@
   // threaded in the product, but some tests may be racy and lazy about our
   // initialization.
   base::AutoLock lock(*list_lock_.Pointer());
-  if (status_ >= DEACTIVATED)
+  if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED)
     return;  // Someone raced in here and beat us.
 
   // Put an alternate timer in place if the environment calls for it, such as
@@ -714,12 +714,12 @@
   // 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);
+    DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), UNINITIALIZED);
     tls_index_.Initialize(&ThreadData::OnThreadTermination);
     DCHECK(tls_index_.initialized());
   } else {
     // TLS was initialzed for us earlier.
-    DCHECK_EQ(status_, DORMANT_DURING_TESTS);
+    DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), DORMANT_DURING_TESTS);
   }
 
   // Incarnation counter is only significant to testing, as it otherwise will
@@ -729,8 +729,8 @@
   // 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);
+  base::subtle::Release_Store(&status_, kInitialStartupState);
+  DCHECK(base::subtle::NoBarrier_Load(&status_) != UNINITIALIZED);
 }
 
 // static
@@ -742,17 +742,17 @@
 
   if (status > DEACTIVATED)
     status = PROFILING_ACTIVE;
-  status_ = status;
+  base::subtle::Release_Store(&status_, status);
 }
 
 // static
 ThreadData::Status ThreadData::status() {
-  return status_;
+  return static_cast<ThreadData::Status>(base::subtle::Acquire_Load(&status_));
 }
 
 // static
 bool ThreadData::TrackingStatus() {
-  return status_ > DEACTIVATED;
+  return base::subtle::Acquire_Load(&status_) > DEACTIVATED;
 }
 
 // static
@@ -817,7 +817,8 @@
   worker_thread_data_creation_count_ = 0;
   cleanup_count_ = 0;
   tls_index_.Set(NULL);
-  status_ = DORMANT_DURING_TESTS;  // Almost UNINITIALIZED.
+  // Almost UNINITIALIZED.
+  base::subtle::Release_Store(&status_, DORMANT_DURING_TESTS);
 
   // To avoid any chance of racing in unit tests, which is the only place we
   // call this function, we may sometimes leak all the data structures we
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 8f83794..e62948d 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -12,6 +12,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/atomicops.h"
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/containers/hash_tables.h"
@@ -199,7 +200,7 @@
  public:
   BirthOnThread(const Location& location, const ThreadData& current);
 
-  const Location location() const { return location_; }
+  const Location& location() const { return location_; }
   const ThreadData* birth_thread() const { return birth_thread_; }
 
  private:
@@ -661,7 +662,7 @@
   static base::LazyInstance<base::Lock>::Leaky list_lock_;
 
   // We set status_ to SHUTDOWN when we shut down the tracking service.
-  static Status status_;
+  static base::subtle::Atomic32 status_;
 
   // Link to next instance (null terminated list).  Used to globally track all
   // registered instances (corresponds to all registered threads where we keep
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc
index cdbf9ac..09d7653 100644
--- a/base/tracked_objects_unittest.cc
+++ b/base/tracked_objects_unittest.cc
@@ -240,7 +240,7 @@
   ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
 
   scoped_ptr<DeathData> data(new DeathData());
-  ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+  ASSERT_NE(data, nullptr);
   EXPECT_EQ(data->run_duration_sum(), 0);
   EXPECT_EQ(data->run_duration_max(), 0);
   EXPECT_EQ(data->run_duration_sample(), 0);
@@ -279,7 +279,7 @@
   ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
 
   scoped_ptr<DeathData> data(new DeathData());
-  ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+  ASSERT_NE(data, nullptr);
 
   int32 run_ms = 42;
   int32 queue_ms = 8;
diff --git a/base/tuple.h b/base/tuple.h
index 4628aa9..5a04858 100644
--- a/base/tuple.h
+++ b/base/tuple.h
@@ -30,6 +30,8 @@
 
 #include "base/bind_helpers.h"
 
+namespace base {
+
 // Index sequences
 //
 // Minimal clone of the similarly-named C++14 functionality.
@@ -148,7 +150,7 @@
 struct TupleLeaf;
 
 template <typename... Ts>
-struct Tuple : TupleBase<Ts...> {
+struct Tuple final : TupleBase<Ts...> {
   Tuple() : TupleBase<Ts...>() {}
   explicit Tuple(typename TupleTraits<Ts>::ParamType... args)
       : TupleBase<Ts...>(args...) {}
@@ -156,7 +158,7 @@
 
 // Avoids ambiguity between Tuple's two constructors.
 template <>
-struct Tuple<> {};
+struct Tuple<> final {};
 
 template <size_t... Ns, typename... Ts>
 struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... {
@@ -181,9 +183,9 @@
 // Allows accessing an arbitrary tuple element by index.
 //
 // Example usage:
-//   Tuple<int, double> t2;
-//   get<0>(t2) = 42;
-//   get<1>(t2) = 3.14;
+//   base::Tuple<int, double> t2;
+//   base::get<0>(t2) = 42;
+//   base::get<1>(t2) = 3.14;
 
 template <size_t I, typename T>
 T& get(TupleLeaf<I, T>& leaf) {
@@ -329,4 +331,6 @@
                        MakeIndexSequence<sizeof...(OutTs)>());
 }
 
+}  // namespace base
+
 #endif  // BASE_TUPLE_H_
diff --git a/base/tuple_unittest.cc b/base/tuple_unittest.cc
index 5b43aff..55a9139 100644
--- a/base/tuple_unittest.cc
+++ b/base/tuple_unittest.cc
@@ -7,6 +7,8 @@
 #include "base/compiler_specific.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace base {
+
 namespace {
 
 void DoAdd(int a, int b, int c, int* res) {
@@ -30,14 +32,15 @@
 }  // namespace
 
 TEST(TupleTest, Basic) {
-  Tuple<> t0 = MakeTuple();
+  base::Tuple<> t0 = base::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));
+  base::Tuple<int> t1(1);
+  base::Tuple<int, const char*> t2 =
+      base::MakeTuple(1, static_cast<const char*>("wee"));
+  base::Tuple<int, int, int> t3(1, 2, 3);
+  base::Tuple<int, int, int, int*> t4(1, 2, 3, &get<0>(t1));
+  base::Tuple<int, int, int, int, int*> t5(1, 2, 3, 4, &get<0>(t4));
+  base::Tuple<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &get<0>(t4));
 
   EXPECT_EQ(1, get<0>(t1));
   EXPECT_EQ(1, get<0>(t2));
@@ -62,7 +65,7 @@
   EXPECT_EQ(6, get<0>(t1));
 
   int res = 0;
-  DispatchToFunction(&DoAdd, MakeTuple(9, 8, 7, &res));
+  DispatchToFunction(&DoAdd, base::MakeTuple(9, 8, 7, &res));
   EXPECT_EQ(24, res);
 
   Addy addy;
@@ -108,7 +111,7 @@
   bool res = false;
 
   // Creating the tuple should copy the class to store internally in the tuple.
-  Tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res);
+  base::Tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res);
   get<1>(tuple) = &get<0>(tuple);
   EXPECT_EQ(2, CopyLogger::TimesConstructed);
   EXPECT_EQ(1, CopyLogger::TimesCopied);
@@ -127,3 +130,5 @@
   EXPECT_EQ(3, CopyLogger::TimesConstructed);
   EXPECT_EQ(2, CopyLogger::TimesCopied);
 }
+
+}  // namespace base
diff --git a/base/values.cc b/base/values.cc
index 4093eba..ab3c38a 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -9,6 +9,7 @@
 #include <algorithm>
 #include <cmath>
 #include <ostream>
+#include <utility>
 
 #include "base/json/json_writer.h"
 #include "base/logging.h"
@@ -20,46 +21,49 @@
 
 namespace {
 
+scoped_ptr<Value> CopyWithoutEmptyChildren(const Value& node);
+
 // Make a deep copy of |node|, but don't include empty lists or dictionaries
 // in the copy. It's possible for this function to return NULL and it
 // expects |node| to always be non-NULL.
-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;
+scoped_ptr<ListValue> CopyListWithoutEmptyChildren(const ListValue& list) {
+  scoped_ptr<ListValue> copy;
+  for (ListValue::const_iterator it = list.begin(); it != list.end(); ++it) {
+    scoped_ptr<Value> child_copy = CopyWithoutEmptyChildren(**it);
+    if (child_copy) {
+      if (!copy)
+        copy.reset(new ListValue);
+      copy->Append(std::move(child_copy));
     }
+  }
+  return copy;
+}
 
-    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;
+scoped_ptr<DictionaryValue> CopyDictionaryWithoutEmptyChildren(
+    const DictionaryValue& dict) {
+  scoped_ptr<DictionaryValue> copy;
+  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    scoped_ptr<Value> child_copy = CopyWithoutEmptyChildren(it.value());
+    if (child_copy) {
+      if (!copy)
+        copy.reset(new DictionaryValue);
+      copy->SetWithoutPathExpansion(it.key(), std::move(child_copy));
     }
+  }
+  return copy;
+}
+
+scoped_ptr<Value> CopyWithoutEmptyChildren(const Value& node) {
+  switch (node.GetType()) {
+    case Value::TYPE_LIST:
+      return CopyListWithoutEmptyChildren(static_cast<const ListValue&>(node));
+
+    case Value::TYPE_DICTIONARY:
+      return CopyDictionaryWithoutEmptyChildren(
+          static_cast<const DictionaryValue&>(node));
 
     default:
-      // For everything else, just make a copy.
-      return node->DeepCopy();
+      return node.CreateDeepCopy();
   }
 }
 
@@ -310,10 +314,7 @@
 }
 
 BinaryValue::BinaryValue(scoped_ptr<char[]> buffer, size_t size)
-    : Value(TYPE_BINARY),
-      buffer_(buffer.Pass()),
-      size_(size) {
-}
+    : Value(TYPE_BINARY), buffer_(std::move(buffer)), size_(size) {}
 
 BinaryValue::~BinaryValue() {
 }
@@ -324,7 +325,7 @@
   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);
+  return new BinaryValue(std::move(scoped_buffer_copy), size);
 }
 
 bool BinaryValue::GetAsBinary(const BinaryValue** out_value) const {
@@ -348,6 +349,16 @@
 
 ///////////////////// DictionaryValue ////////////////////
 
+// static
+scoped_ptr<DictionaryValue> DictionaryValue::From(scoped_ptr<Value> value) {
+  DictionaryValue* out;
+  if (value && value->GetAsDictionary(&out)) {
+    ignore_result(value.release());
+    return make_scoped_ptr(out);
+  }
+  return nullptr;
+}
+
 DictionaryValue::DictionaryValue()
     : Value(TYPE_DICTIONARY) {
 }
@@ -406,7 +417,8 @@
     current_path.erase(0, delimiter_position + 1);
   }
 
-  current_dictionary->SetWithoutPathExpansion(current_path, in_value.Pass());
+  current_dictionary->SetWithoutPathExpansion(current_path,
+                                              std::move(in_value));
 }
 
 void DictionaryValue::Set(const std::string& path, Value* in_value) {
@@ -479,27 +491,30 @@
   SetWithoutPathExpansion(path, new StringValue(in_value));
 }
 
-bool DictionaryValue::Get(const std::string& path,
+bool DictionaryValue::Get(StringPiece path,
                           const Value** out_value) const {
   DCHECK(IsStringUTF8(path));
-  std::string current_path(path);
+  StringPiece current_path(path);
   const DictionaryValue* current_dictionary = this;
   for (size_t delimiter_position = current_path.find('.');
        delimiter_position != std::string::npos;
        delimiter_position = current_path.find('.')) {
     const DictionaryValue* child_dictionary = NULL;
-    if (!current_dictionary->GetDictionary(
-            current_path.substr(0, delimiter_position), &child_dictionary))
+    if (!current_dictionary->GetDictionaryWithoutPathExpansion(
+            current_path.substr(0, delimiter_position).as_string(),
+            &child_dictionary)) {
       return false;
+    }
 
     current_dictionary = child_dictionary;
-    current_path.erase(0, delimiter_position + 1);
+    current_path = current_path.substr(delimiter_position + 1);
   }
 
-  return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
+  return current_dictionary->GetWithoutPathExpansion(current_path.as_string(),
+                                                     out_value);
 }
 
-bool DictionaryValue::Get(const std::string& path, Value** out_value)  {
+bool DictionaryValue::Get(StringPiece path, Value** out_value)  {
   return static_cast<const DictionaryValue&>(*this).Get(
       path,
       const_cast<const Value**>(out_value));
@@ -585,7 +600,7 @@
       const_cast<const BinaryValue**>(out_value));
 }
 
-bool DictionaryValue::GetDictionary(const std::string& path,
+bool DictionaryValue::GetDictionary(StringPiece path,
                                     const DictionaryValue** out_value) const {
   const Value* value;
   bool result = Get(path, &value);
@@ -598,7 +613,7 @@
   return true;
 }
 
-bool DictionaryValue::GetDictionary(const std::string& path,
+bool DictionaryValue::GetDictionary(StringPiece path,
                                     DictionaryValue** out_value) {
   return static_cast<const DictionaryValue&>(*this).GetDictionary(
       path,
@@ -789,9 +804,12 @@
   return result;
 }
 
-DictionaryValue* DictionaryValue::DeepCopyWithoutEmptyChildren() const {
-  Value* copy = CopyWithoutEmptyChildren(this);
-  return copy ? static_cast<DictionaryValue*>(copy) : new DictionaryValue;
+scoped_ptr<DictionaryValue> DictionaryValue::DeepCopyWithoutEmptyChildren()
+    const {
+  scoped_ptr<DictionaryValue> copy = CopyDictionaryWithoutEmptyChildren(*this);
+  if (!copy)
+    copy.reset(new DictionaryValue);
+  return copy;
 }
 
 void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
@@ -861,6 +879,16 @@
 
 ///////////////////// ListValue ////////////////////
 
+// static
+scoped_ptr<ListValue> ListValue::From(scoped_ptr<Value> value) {
+  ListValue* out;
+  if (value && value->GetAsList(&out)) {
+    ignore_result(value.release());
+    return make_scoped_ptr(out);
+  }
+  return nullptr;
+}
+
 ListValue::ListValue() : Value(TYPE_LIST) {
 }
 
@@ -1168,9 +1196,7 @@
 
 std::ostream& operator<<(std::ostream& out, const Value& value) {
   std::string json;
-  JSONWriter::WriteWithOptions(&value,
-                               JSONWriter::OPTIONS_PRETTY_PRINT,
-                               &json);
+  JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   return out << json;
 }
 
diff --git a/base/values.h b/base/values.h
index e32edec..a64f6a8 100644
--- a/base/values.h
+++ b/base/values.h
@@ -30,6 +30,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
 
 namespace base {
 
@@ -208,6 +209,9 @@
 // are |std::string|s and should be UTF-8 encoded.
 class BASE_EXPORT DictionaryValue : public Value {
  public:
+  // Returns |value| if it is a dictionary, nullptr otherwise.
+  static scoped_ptr<DictionaryValue> From(scoped_ptr<Value> value);
+
   DictionaryValue();
   ~DictionaryValue() override;
 
@@ -270,8 +274,8 @@
   // 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);
+  bool Get(StringPiece path, const Value** out_value) const;
+  bool Get(StringPiece path, Value** out_value);
 
   // These are convenience forms of Get().  The value will be retrieved
   // and the return value will be true if the path is valid and the value at
@@ -287,9 +291,9 @@
   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,
+  bool GetDictionary(StringPiece path,
                      const DictionaryValue** out_value) const;
-  bool GetDictionary(const std::string& path, DictionaryValue** out_value);
+  bool GetDictionary(StringPiece path, DictionaryValue** out_value);
   bool GetList(const std::string& path, const ListValue** out_value) const;
   bool GetList(const std::string& path, ListValue** out_value);
 
@@ -338,7 +342,7 @@
 
   // 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;
+  scoped_ptr<DictionaryValue> DeepCopyWithoutEmptyChildren() const;
 
   // Merge |dictionary| into this dictionary. This is done recursively, i.e. any
   // sub-dictionaries will be merged as well. In case of key collisions, the
@@ -386,6 +390,9 @@
   typedef ValueVector::iterator iterator;
   typedef ValueVector::const_iterator const_iterator;
 
+  // Returns |value| if it is a list, nullptr otherwise.
+  static scoped_ptr<ListValue> From(scoped_ptr<Value> value);
+
   ListValue();
   ~ListValue() override;
 
@@ -524,7 +531,8 @@
   // 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;
+  virtual scoped_ptr<Value> Deserialize(int* error_code,
+                                        std::string* error_str) = 0;
 };
 
 // Stream operator so Values can be used in assertion statements.  In order that
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 6466a96..a5bd002 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <limits>
+#include <utility>
 
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
@@ -34,13 +35,13 @@
     settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
 
   scoped_ptr<ListValue> new_toolbar_bookmarks(new ListValue);
-  settings.Set("global.toolbar.bookmarks", new_toolbar_bookmarks.Pass());
+  settings.Set("global.toolbar.bookmarks", std::move(new_toolbar_bookmarks));
   ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
 
   scoped_ptr<DictionaryValue> new_bookmark(new DictionaryValue);
   new_bookmark->SetString("name", "Froogle");
   new_bookmark->SetString("url", "http://froogle.com");
-  toolbar_bookmarks->Append(new_bookmark.Pass());
+  toolbar_bookmarks->Append(std::move(new_bookmark));
 
   ListValue* bookmark_list;
   ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list));
@@ -114,7 +115,7 @@
   // Test the common case of a non-empty buffer
   scoped_ptr<char[]> buffer(new char[15]);
   char* original_buffer = buffer.get();
-  binary.reset(new BinaryValue(buffer.Pass(), 15));
+  binary.reset(new BinaryValue(std::move(buffer), 15));
   ASSERT_TRUE(binary.get());
   ASSERT_TRUE(binary->GetBuffer());
   ASSERT_EQ(original_buffer, binary->GetBuffer());
@@ -250,7 +251,7 @@
     ListValue list;
     scoped_ptr<DeletionTestValue> value(new DeletionTestValue(&deletion_flag));
     DeletionTestValue* original_value = value.get();
-    list.Append(value.Pass());
+    list.Append(std::move(value));
     EXPECT_FALSE(deletion_flag);
     size_t index = 0;
     list.Remove(*original_value, &index);
@@ -393,45 +394,45 @@
   DictionaryValue original_dict;
   scoped_ptr<Value> scoped_null = Value::CreateNullValue();
   Value* original_null = scoped_null.get();
-  original_dict.Set("null", scoped_null.Pass());
+  original_dict.Set("null", std::move(scoped_null));
   scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
   FundamentalValue* original_bool = scoped_bool.get();
-  original_dict.Set("bool", scoped_bool.Pass());
+  original_dict.Set("bool", std::move(scoped_bool));
   scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
   FundamentalValue* original_int = scoped_int.get();
-  original_dict.Set("int", scoped_int.Pass());
+  original_dict.Set("int", std::move(scoped_int));
   scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
   FundamentalValue* original_double = scoped_double.get();
-  original_dict.Set("double", scoped_double.Pass());
+  original_dict.Set("double", std::move(scoped_double));
   scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
   StringValue* original_string = scoped_string.get();
-  original_dict.Set("string", scoped_string.Pass());
+  original_dict.Set("string", std::move(scoped_string));
   scoped_ptr<StringValue> scoped_string16(
       new StringValue(ASCIIToUTF16("hello16")));
   StringValue* original_string16 = scoped_string16.get();
-  original_dict.Set("string16", scoped_string16.Pass());
+  original_dict.Set("string16", std::move(scoped_string16));
 
   scoped_ptr<char[]> original_buffer(new char[42]);
   memset(original_buffer.get(), '!', 42);
   scoped_ptr<BinaryValue> scoped_binary(
-      new BinaryValue(original_buffer.Pass(), 42));
+      new BinaryValue(std::move(original_buffer), 42));
   BinaryValue* original_binary = scoped_binary.get();
-  original_dict.Set("binary", scoped_binary.Pass());
+  original_dict.Set("binary", std::move(scoped_binary));
 
   scoped_ptr<ListValue> scoped_list(new ListValue());
   Value* original_list = scoped_list.get();
   scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0));
   Value* original_list_element_0 = scoped_list_element_0.get();
-  scoped_list->Append(scoped_list_element_0.Pass());
+  scoped_list->Append(std::move(scoped_list_element_0));
   scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1));
   Value* original_list_element_1 = scoped_list_element_1.get();
-  scoped_list->Append(scoped_list_element_1.Pass());
-  original_dict.Set("list", scoped_list.Pass());
+  scoped_list->Append(std::move(scoped_list_element_1));
+  original_dict.Set("list", std::move(scoped_list));
 
   scoped_ptr<DictionaryValue> scoped_nested_dictionary(new DictionaryValue());
   Value* original_nested_dictionary = scoped_nested_dictionary.get();
   scoped_nested_dictionary->SetString("key", "value");
-  original_dict.Set("dictionary", scoped_nested_dictionary.Pass());
+  original_dict.Set("dictionary", std::move(scoped_nested_dictionary));
 
   scoped_ptr<DictionaryValue> copy_dict = original_dict.CreateDeepCopy();
   ASSERT_TRUE(copy_dict.get());
@@ -568,9 +569,9 @@
   list->Append(make_scoped_ptr(new DictionaryValue));
   scoped_ptr<Value> list_copy(list->CreateDeepCopy());
 
-  dv.Set("f", list.Pass());
+  dv.Set("f", std::move(list));
   EXPECT_FALSE(dv.Equals(copy.get()));
-  copy->Set("f", list_copy.Pass());
+  copy->Set("f", std::move(list_copy));
   EXPECT_TRUE(dv.Equals(copy.get()));
 
   original_list->Append(make_scoped_ptr(new FundamentalValue(true)));
@@ -611,38 +612,38 @@
   DictionaryValue original_dict;
   scoped_ptr<Value> scoped_null(Value::CreateNullValue());
   Value* original_null = scoped_null.get();
-  original_dict.Set("null", scoped_null.Pass());
+  original_dict.Set("null", std::move(scoped_null));
   scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
   Value* original_bool = scoped_bool.get();
-  original_dict.Set("bool", scoped_bool.Pass());
+  original_dict.Set("bool", std::move(scoped_bool));
   scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
   Value* original_int = scoped_int.get();
-  original_dict.Set("int", scoped_int.Pass());
+  original_dict.Set("int", std::move(scoped_int));
   scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
   Value* original_double = scoped_double.get();
-  original_dict.Set("double", scoped_double.Pass());
+  original_dict.Set("double", std::move(scoped_double));
   scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
   Value* original_string = scoped_string.get();
-  original_dict.Set("string", scoped_string.Pass());
+  original_dict.Set("string", std::move(scoped_string));
   scoped_ptr<StringValue> scoped_string16(
       new StringValue(ASCIIToUTF16("hello16")));
   Value* original_string16 = scoped_string16.get();
-  original_dict.Set("string16", scoped_string16.Pass());
+  original_dict.Set("string16", std::move(scoped_string16));
 
   scoped_ptr<char[]> original_buffer(new char[42]);
   memset(original_buffer.get(), '!', 42);
   scoped_ptr<BinaryValue> scoped_binary(
-      new BinaryValue(original_buffer.Pass(), 42));
+      new BinaryValue(std::move(original_buffer), 42));
   Value* original_binary = scoped_binary.get();
-  original_dict.Set("binary", scoped_binary.Pass());
+  original_dict.Set("binary", std::move(scoped_binary));
 
   scoped_ptr<ListValue> scoped_list(new ListValue());
   Value* original_list = scoped_list.get();
   scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0));
-  scoped_list->Append(scoped_list_element_0.Pass());
+  scoped_list->Append(std::move(scoped_list_element_0));
   scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1));
-  scoped_list->Append(scoped_list_element_1.Pass());
-  original_dict.Set("list", scoped_list.Pass());
+  scoped_list->Append(std::move(scoped_list_element_1));
+  original_dict.Set("list", std::move(scoped_list));
 
   scoped_ptr<Value> copy_dict = original_dict.CreateDeepCopy();
   scoped_ptr<Value> copy_null = original_null->CreateDeepCopy();
@@ -672,41 +673,41 @@
   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());
+  root = root->DeepCopyWithoutEmptyChildren();
   EXPECT_TRUE(root->empty());
 
   // Make sure we don't prune too much.
   root->SetBoolean("bool", true);
   root->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
   root->SetString("empty_string", std::string());
-  root.reset(root->DeepCopyWithoutEmptyChildren());
+  root = root->DeepCopyWithoutEmptyChildren();
   EXPECT_EQ(2U, root->size());
 
   // Should do nothing.
-  root.reset(root->DeepCopyWithoutEmptyChildren());
+  root = root->DeepCopyWithoutEmptyChildren();
   EXPECT_EQ(2U, root->size());
 
   // Nested test cases.  These should all reduce back to the bool and string
   // set above.
   {
     root->Set("a.b.c.d.e", make_scoped_ptr(new DictionaryValue));
-    root.reset(root->DeepCopyWithoutEmptyChildren());
+    root = root->DeepCopyWithoutEmptyChildren();
     EXPECT_EQ(2U, root->size());
   }
   {
     scoped_ptr<DictionaryValue> inner(new DictionaryValue);
     inner->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
     inner->Set("empty_list", make_scoped_ptr(new ListValue));
-    root->Set("dict_with_empty_children", inner.Pass());
-    root.reset(root->DeepCopyWithoutEmptyChildren());
+    root->Set("dict_with_empty_children", std::move(inner));
+    root = root->DeepCopyWithoutEmptyChildren();
     EXPECT_EQ(2U, root->size());
   }
   {
     scoped_ptr<ListValue> inner(new ListValue);
     inner->Append(make_scoped_ptr(new DictionaryValue));
     inner->Append(make_scoped_ptr(new ListValue));
-    root->Set("list_with_empty_children", inner.Pass());
-    root.reset(root->DeepCopyWithoutEmptyChildren());
+    root->Set("list_with_empty_children", std::move(inner));
+    root = root->DeepCopyWithoutEmptyChildren();
     EXPECT_EQ(2U, root->size());
   }
 
@@ -715,12 +716,12 @@
     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->Set("list_with_empty_children", std::move(inner));
     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());
+    root->Set("dict_with_empty_children", std::move(inner2));
+    root = root->DeepCopyWithoutEmptyChildren();
     EXPECT_EQ(2U, root->size());
   }
 
@@ -730,9 +731,9 @@
     scoped_ptr<ListValue> inner2(new ListValue);
     inner2->Append(make_scoped_ptr(new StringValue("hello")));
     inner->Append(make_scoped_ptr(new DictionaryValue));
-    inner->Append(inner2.Pass());
-    root->Set("list_with_empty_children", inner.Pass());
-    root.reset(root->DeepCopyWithoutEmptyChildren());
+    inner->Append(std::move(inner2));
+    root->Set("list_with_empty_children", std::move(inner));
+    root = root->DeepCopyWithoutEmptyChildren();
     EXPECT_EQ(3U, root->size());
 
     ListValue* inner_value, *inner_value2;
@@ -750,7 +751,7 @@
   scoped_ptr<DictionaryValue> base_sub_dict(new DictionaryValue);
   base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base");
   base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base");
-  base->Set("sub_dict_key", base_sub_dict.Pass());
+  base->Set("sub_dict_key", std::move(base_sub_dict));
 
   scoped_ptr<DictionaryValue> merge(new DictionaryValue);
   merge->SetString("merge_key", "merge_key_value_merge");
@@ -758,7 +759,7 @@
   scoped_ptr<DictionaryValue> merge_sub_dict(new DictionaryValue);
   merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge");
   merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge");
-  merge->Set("sub_dict_key", merge_sub_dict.Pass());
+  merge->Set("sub_dict_key", std::move(merge_sub_dict));
 
   base->MergeDictionary(merge.get());
 
@@ -799,7 +800,7 @@
   EXPECT_EQ("value", value);
 
   scoped_ptr<DictionaryValue> base(new DictionaryValue);
-  base->Set("dict", child.Pass());
+  base->Set("dict", std::move(child));
   EXPECT_EQ(1U, base->size());
 
   DictionaryValue* ptr;
diff --git a/base/version.cc b/base/version.cc
index ede8a45..3677b73 100644
--- a/base/version.cc
+++ b/base/version.cc
@@ -24,15 +24,17 @@
 // 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);
+  std::vector<StringPiece> numbers =
+      SplitStringPiece(version_str, ".", KEEP_WHITESPACE, SPLIT_WANT_ALL);
   if (numbers.empty())
     return false;
 
-  for (std::vector<std::string>::const_iterator it = numbers.begin();
-       it != numbers.end(); ++it) {
-    if (StartsWithASCII(*it, "+", false))
+  for (auto it = numbers.begin(); it != numbers.end(); ++it) {
+    if (StartsWith(*it, "+", CompareCase::SENSITIVE))
       return false;
+
+    // TODO(brettw) when we have a StringPiece version of StringToUint, delete
+    // this string conversion.
     unsigned int num;
     if (!StringToUint(*it, &num))
       return false;
@@ -98,8 +100,8 @@
 // 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);
+  if (EndsWith(version_string, ".*", CompareCase::SENSITIVE))
+    version_string.resize(version_string.size() - 2);
 
   Version version(version_string);
   return version.IsValid();
@@ -117,7 +119,7 @@
   DCHECK(Version::IsValidWildcardString(wildcard_string));
 
   // Default behavior if the string doesn't end with a wildcard.
-  if (!EndsWith(wildcard_string.c_str(), ".*", false)) {
+  if (!EndsWith(wildcard_string, ".*", CompareCase::SENSITIVE)) {
     Version version(wildcard_string);
     DCHECK(version.IsValid());
     return CompareTo(version);
@@ -166,10 +168,10 @@
   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(UintToString(components_[i]));
     version_str.append(".");
   }
-  version_str.append(IntToString(components_[count - 1]));
+  version_str.append(UintToString(components_[count - 1]));
   return version_str;
 }
 
diff --git a/base/win/OWNERS b/base/win/OWNERS
index 8624efe..78473b9 100644
--- a/base/win/OWNERS
+++ b/base/win/OWNERS
@@ -1,3 +1,4 @@
 cpu@chromium.org
 grt@chromium.org
-rvargas@chromium.org
+jschuh@chromium.org
+scottmg@chromium.org
diff --git a/base/win/event_trace_controller.cc b/base/win/event_trace_controller.cc
index 9a35a6b..ff392a3 100644
--- a/base/win/event_trace_controller.cc
+++ b/base/win/event_trace_controller.cc
@@ -46,7 +46,8 @@
 }
 
 EtwTraceController::~EtwTraceController() {
-  Stop(NULL);
+  if (session_)
+    Stop(NULL);
 }
 
 HRESULT EtwTraceController::Start(const wchar_t* session_name,
diff --git a/base/win/event_trace_controller_unittest.cc b/base/win/event_trace_controller_unittest.cc
index a2cd81c..c947ed7 100644
--- a/base/win/event_trace_controller_unittest.cc
+++ b/base/win/event_trace_controller_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/win/event_trace_controller.h"
 #include "base/win/event_trace_provider.h"
 #include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -179,7 +180,8 @@
   base::DeleteFile(temp, false);
 }
 
-TEST_F(EtwTraceControllerTest, EnableDisable) {
+// This test is flaky for unclear reasons. See bugs 525297 and 534184
+TEST_F(EtwTraceControllerTest, DISABLED_EnableDisable) {
   TestingProvider provider(test_provider_);
 
   EXPECT_EQ(ERROR_SUCCESS, provider.Register());
@@ -221,13 +223,20 @@
   EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level());
   EXPECT_EQ(kTestProviderFlags, provider.enable_flags());
 
-  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
-
+  // Consume the callback event of the previous controller.EnableProvider().
   provider.WaitForCallback();
 
-  // Session should have wound down.
-  EXPECT_EQ(0, provider.enable_level());
-  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+  // Windows 7 does not call the callback when Stop() is called so we
+  // can't wait, and enable_level and enable_flags are not zeroed.
+  if (base::win::GetVersion() >= VERSION_WIN8) {
+    provider.WaitForCallback();
+
+    // Session should have wound down.
+    EXPECT_EQ(0, provider.enable_level());
+    EXPECT_EQ(0, provider.enable_flags());
+  }
 }
 
 }  // namespace win
diff --git a/base/win/i18n.cc b/base/win/i18n.cc
index 9e523a1..a26e274 100644
--- a/base/win/i18n.cc
+++ b/base/win/i18n.cc
@@ -32,8 +32,9 @@
   &kThreadLanguagesFunctionName[0]
 };
 
-COMPILE_ASSERT(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames),
-               language_function_enum_and_names_out_of_sync);
+static_assert(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames),
+              "LanguageFunction enum and kLanguageFunctionNames array must be "
+              "kept in sync");
 
 // Calls one of the MUI Get*PreferredUILanguages functions, placing the result
 // in |languages|.  |function| identifies the function to call and |flags| is
diff --git a/base/win/iat_patch_function.cc b/base/win/iat_patch_function.cc
index 13acd65..be7c545 100644
--- a/base/win/iat_patch_function.cc
+++ b/base/win/iat_patch_function.cc
@@ -67,8 +67,9 @@
     }
 
     // portability check
-    COMPILE_ASSERT(sizeof(iat->u1.Function) ==
-      sizeof(intercept_information->new_function), unknown_IAT_thunk_format);
+    static_assert(
+        sizeof(iat->u1.Function) == sizeof(intercept_information->new_function),
+        "unknown IAT thunk format");
 
     // Patch the function.
     intercept_information->return_code =
@@ -219,9 +220,9 @@
 
 IATPatchFunction::IATPatchFunction()
     : module_handle_(NULL),
+      intercept_function_(NULL),
       original_function_(NULL),
-      iat_thunk_(NULL),
-      intercept_function_(NULL) {
+      iat_thunk_(NULL) {
 }
 
 IATPatchFunction::~IATPatchFunction() {
diff --git a/base/win/message_window.cc b/base/win/message_window.cc
index 0b4b29f..57fe64c 100644
--- a/base/win/message_window.cc
+++ b/base/win/message_window.cc
@@ -7,7 +7,6 @@
 #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";
@@ -121,10 +120,6 @@
                                            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));
 
diff --git a/base/win/metro.cc b/base/win/metro.cc
index 7946698..c3310c8 100644
--- a/base/win/metro.cc
+++ b/base/win/metro.cc
@@ -5,10 +5,16 @@
 #include "base/win/metro.h"
 
 #include "base/strings/string_util.h"
+#include "base/win/windows_version.h"
 
 namespace base {
 namespace win {
 
+bool IsChromeMetroSupported() {
+  const Version win_version = GetVersion();
+  return win_version >= VERSION_WIN8 && win_version < VERSION_WIN10;
+}
+
 HMODULE GetMetroModule() {
   const HMODULE kUninitialized = reinterpret_cast<HMODULE>(1);
   static HMODULE metro_module = kUninitialized;
diff --git a/base/win/metro.h b/base/win/metro.h
index 0696006..15a89c2 100644
--- a/base/win/metro.h
+++ b/base/win/metro.h
@@ -63,6 +63,9 @@
   wchar_t* url;
 };
 
+// Returns true if Chrome supports Metro-mode on this Windows version.
+BASE_EXPORT bool IsChromeMetroSupported();
+
 // 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();
diff --git a/base/win/object_watcher.cc b/base/win/object_watcher.cc
index 5ebe185..93efd06 100644
--- a/base/win/object_watcher.cc
+++ b/base/win/object_watcher.cc
@@ -16,6 +16,7 @@
     : object_(NULL),
       wait_object_(NULL),
       origin_loop_(NULL),
+      run_once_(true),
       weak_factory_(this) {
 }
 
@@ -23,36 +24,13 @@
   StopWatching();
 }
 
-bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
-  CHECK(delegate);
-  if (wait_object_) {
-    NOTREACHED() << "Already watching an object";
-    return false;
-  }
+bool ObjectWatcher::StartWatchingOnce(HANDLE object, Delegate* delegate) {
+  return StartWatchingInternal(object, delegate, true);
+}
 
-  // 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::StartWatchingMultipleTimes(HANDLE object,
+                                               Delegate* delegate) {
+  return StartWatchingInternal(object, delegate, false);
 }
 
 bool ObjectWatcher::StopWatching() {
@@ -93,7 +71,44 @@
   // 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();
+  if (that->run_once_)
+    that->callback_.Reset();
+}
+
+bool ObjectWatcher::StartWatchingInternal(HANDLE object, Delegate* delegate,
+                                          bool execute_only_once) {
+  CHECK(delegate);
+  if (wait_object_) {
+    NOTREACHED() << "Already watching an object";
+    return false;
+  }
+  run_once_ = execute_only_once;
+
+  // 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;
+  if (run_once_)
+    wait_flags |= 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;
 }
 
 void ObjectWatcher::Signal(Delegate* delegate) {
@@ -101,7 +116,8 @@
   // StartWatching(). As a result, we save any state we need and clear previous
   // watcher state before signaling the delegate.
   HANDLE object = object_;
-  StopWatching();
+  if (run_once_)
+    StopWatching();
   delegate->OnObjectSignaled(object);
 }
 
diff --git a/base/win/object_watcher.h b/base/win/object_watcher.h
index d68d935..f4d6085 100644
--- a/base/win/object_watcher.h
+++ b/base/win/object_watcher.h
@@ -26,16 +26,16 @@
 //
 // Typical usage:
 //
-//   class MyClass : public base::ObjectWatcher::Delegate {
+//   class MyClass : public base::win::ObjectWatcher::Delegate {
 //    public:
 //     void DoStuffWhenSignaled(HANDLE object) {
-//       watcher_.StartWatching(object, this);
+//       watcher_.StartWatchingOnce(object, this);
 //     }
-//     virtual void OnObjectSignaled(HANDLE object) {
+//     void OnObjectSignaled(HANDLE object) override {
 //       // OK, time to do stuff!
 //     }
 //    private:
-//     base::ObjectWatcher watcher_;
+//     base::win::ObjectWatcher watcher_;
 //   };
 //
 // In the above example, MyClass wants to "do stuff" when object becomes
@@ -59,19 +59,23 @@
   ~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
+  // where StartWatchingOnce 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);
+  bool StartWatchingOnce(HANDLE object, Delegate* delegate);
+
+  // Notifies the delegate, on the thread where this method is called, each time
+  // the object is set. By definition, the handle must be an auto-reset object.
+  // The caller must ensure that it (or any Windows system code) doesn't reset
+  // the event or else the delegate won't be called.
+  // Returns true if the watch was started.  Otherwise, false is returned.
+  bool StartWatchingMultipleTimes(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.
@@ -84,6 +88,10 @@
   // Called on a background thread when done waiting.
   static void CALLBACK DoneWaiting(void* param, BOOLEAN timed_out);
 
+  // Helper used by StartWatchingOnce and StartWatchingMultipleTimes.
+  bool StartWatchingInternal(HANDLE object, Delegate* delegate,
+                             bool execute_only_once);
+
   void Signal(Delegate* delegate);
 
   // MessageLoop::DestructionObserver implementation:
@@ -94,7 +102,7 @@
   HANDLE object_;             // The object being watched
   HANDLE wait_object_;        // Returned by RegisterWaitForSingleObject
   MessageLoop* origin_loop_;  // Used to get back to the origin thread
-
+  bool run_once_;
   WeakPtrFactory<ObjectWatcher> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ObjectWatcher);
diff --git a/base/win/object_watcher_unittest.cc b/base/win/object_watcher_unittest.cc
index b30ca41..511ec49 100644
--- a/base/win/object_watcher_unittest.cc
+++ b/base/win/object_watcher_unittest.cc
@@ -42,7 +42,7 @@
   HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
 
   QuitDelegate delegate;
-  bool ok = watcher.StartWatching(event, &delegate);
+  bool ok = watcher.StartWatchingOnce(event, &delegate);
   EXPECT_TRUE(ok);
   EXPECT_TRUE(watcher.IsWatching());
   EXPECT_EQ(event, watcher.GetWatchedObject());
@@ -64,7 +64,7 @@
   HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
 
   QuitDelegate delegate;
-  bool ok = watcher.StartWatching(event, &delegate);
+  bool ok = watcher.StartWatchingOnce(event, &delegate);
   EXPECT_TRUE(ok);
 
   watcher.StopWatching();
@@ -83,7 +83,7 @@
   // A manual-reset event that is not yet signaled.
   HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
 
-  bool ok = watcher.StartWatching(event, &delegate);
+  bool ok = watcher.StartWatchingOnce(event, &delegate);
   EXPECT_TRUE(ok);
 
   SetEvent(event);
@@ -110,7 +110,7 @@
   HANDLE event = CreateEvent(NULL, TRUE, TRUE, NULL);
 
   QuitDelegate delegate;
-  bool ok = watcher.StartWatching(event, &delegate);
+  bool ok = watcher.StartWatchingOnce(event, &delegate);
   EXPECT_TRUE(ok);
 
   MessageLoop::current()->Run();
@@ -130,12 +130,53 @@
       MessageLoop message_loop(message_loop_type);
 
       QuitDelegate delegate;
-      watcher.StartWatching(event, &delegate);
+      watcher.StartWatchingOnce(event, &delegate);
     }
   }
   CloseHandle(event);
 }
 
+class QuitAfterMultipleDelegate : public ObjectWatcher::Delegate {
+ public:
+  QuitAfterMultipleDelegate(HANDLE event, int iterations)
+      : event_(event), iterations_(iterations) {}
+  void OnObjectSignaled(HANDLE object) override {
+    if (--iterations_) {
+      SetEvent(event_);
+    } else {
+      MessageLoop::current()->QuitWhenIdle();
+    }
+  }
+
+ private:
+  HANDLE event_;
+  int iterations_;
+};
+
+void RunTest_ExecuteMultipleTimes(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+  EXPECT_FALSE(watcher.IsWatching());
+
+  // An auto-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+  QuitAfterMultipleDelegate delegate(event, 2);
+  bool ok = watcher.StartWatchingMultipleTimes(event, &delegate);
+  EXPECT_TRUE(ok);
+  EXPECT_TRUE(watcher.IsWatching());
+  EXPECT_EQ(event, watcher.GetWatchedObject());
+
+  SetEvent(event);
+
+  MessageLoop::current()->Run();
+
+  EXPECT_TRUE(watcher.IsWatching());
+  EXPECT_TRUE(watcher.StopWatching());
+  CloseHandle(event);
+}
+
 }  // namespace
 
 //-----------------------------------------------------------------------------
@@ -170,5 +211,11 @@
   RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI);
 }
 
+TEST(ObjectWatcherTest, ExecuteMultipleTimes) {
+  RunTest_ExecuteMultipleTimes(MessageLoop::TYPE_DEFAULT);
+  RunTest_ExecuteMultipleTimes(MessageLoop::TYPE_IO);
+  RunTest_ExecuteMultipleTimes(MessageLoop::TYPE_UI);
+}
+
 }  // namespace win
 }  // namespace base
diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc
index 692b7b6..e67eb08 100644
--- a/base/win/pe_image.cc
+++ b/base/win/pe_image.cc
@@ -20,55 +20,56 @@
 
 namespace {
 
-  // PdbInfo Signature
-  const DWORD kPdbInfoSignature = 'SDSR';
+// 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));
+// 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;
   }
 
-  struct PdbInfo {
-    DWORD Signature;
-    GUID Guid;
-    DWORD Age;
-    char PdbFileName[1];
-  };
+  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);
+  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,
+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);
+                             LPCSTR module,
+                             PIMAGE_THUNK_DATA name_table,
+                             PIMAGE_THUNK_DATA 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);
+                                       module, name_table, iat, storage.cookie);
 }
 
 void PEImage::set_module(HMODULE module) {
@@ -439,8 +440,6 @@
   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
@@ -448,33 +447,25 @@
     bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
 
     if (rvas) {
-      module_name = reinterpret_cast<LPCSTR>(
-                        RVAToAddr(delay_descriptor->rvaDLLName));
+      module_name =
+          reinterpret_cast<LPCSTR>(RVAToAddr(delay_descriptor->rvaDLLName));
       name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
-                       RVAToAddr(delay_descriptor->rvaINT));
+          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));
+          RVAToAddr(delay_descriptor->rvaIAT));
     } 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);
+      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))
+                  cookie))
       return false;
   }
 
@@ -486,12 +477,7 @@
                                       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;
@@ -553,13 +539,13 @@
   return true;
 }
 
-bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const {
+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 {
+                                      DWORD* on_disk_offset) const {
   if (NULL == address)
     return false;
 
diff --git a/base/win/pe_image.h b/base/win/pe_image.h
index 343d286..ba21d85 100644
--- a/base/win/pe_image.h
+++ b/base/win/pe_image.h
@@ -69,8 +69,6 @@
                                                 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.
@@ -204,8 +202,6 @@
                                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.
diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc
index 28b65a4..92510bf 100644
--- a/base/win/pe_image_unittest.cc
+++ b/base/win/pe_image_unittest.cc
@@ -67,8 +67,6 @@
                                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)++;
diff --git a/base/win/process_startup_helper.cc b/base/win/process_startup_helper.cc
new file mode 100644
index 0000000..7a01211
--- /dev/null
+++ b/base/win/process_startup_helper.cc
@@ -0,0 +1,55 @@
+// 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/win/process_startup_helper.h"
+
+#include <crtdbg.h>
+#include <new.h>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+
+namespace {
+
+#pragma optimize("", off)
+// Handlers for invalid parameter and pure call. They generate a breakpoint to
+// tell breakpad that it needs to dump the process.
+void InvalidParameter(const wchar_t* expression, const wchar_t* function,
+                      const wchar_t* file, unsigned int line,
+                      uintptr_t reserved) {
+  __debugbreak();
+  _exit(1);
+}
+
+void PureCall() {
+  __debugbreak();
+  _exit(1);
+}
+#pragma optimize("", on)
+
+}  // namespace
+
+namespace base {
+namespace win {
+
+// Register the invalid param handler and pure call handler to be able to
+// notify breakpad when it happens.
+void RegisterInvalidParamHandler() {
+  _set_invalid_parameter_handler(InvalidParameter);
+  _set_purecall_handler(PureCall);
+}
+
+void SetupCRT(const CommandLine& command_line) {
+#if defined(_CRTDBG_MAP_ALLOC)
+  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+#else
+  if (!command_line.HasSwitch(switches::kDisableBreakpad)) {
+    _CrtSetReportMode(_CRT_ASSERT, 0);
+  }
+#endif
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/process_startup_helper.h b/base/win/process_startup_helper.h
new file mode 100644
index 0000000..f633dda
--- /dev/null
+++ b/base/win/process_startup_helper.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_PROCESS_STARTUP_HELPER_H_
+#define BASE_WIN_PROCESS_STARTUP_HELPER_H_
+
+#include "base/base_export.h"
+
+namespace base {
+
+class CommandLine;
+
+namespace win {
+
+// Register the invalid param handler and pure call handler to be able to
+// notify breakpad when it happens.
+BASE_EXPORT void RegisterInvalidParamHandler();
+
+// Sets up the CRT's debugging macros to output to stdout.
+BASE_EXPORT void SetupCRT(const CommandLine& command_line);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_PROCESS_STARTUP_HELPER_H_
diff --git a/base/win/registry.cc b/base/win/registry.cc
index 47afcbf..5d75c96 100644
--- a/base/win/registry.cc
+++ b/base/win/registry.cc
@@ -82,7 +82,7 @@
   }
 
   callback_ = callback;
-  return object_watcher_.StartWatching(watch_event_.Get(), this);
+  return object_watcher_.StartWatchingOnce(watch_event_.Get(), this);
 }
 
 // RegKey ----------------------------------------------------------------------
@@ -364,7 +364,7 @@
   DWORD type = REG_MULTI_SZ;
   DWORD size = 0;
   LONG result = ReadValue(name, NULL, &size, &type);
-  if (FAILED(result) || size == 0)
+  if (result != ERROR_SUCCESS || size == 0)
     return result;
 
   if (type != REG_MULTI_SZ)
@@ -372,7 +372,7 @@
 
   std::vector<wchar_t> buffer(size / sizeof(wchar_t));
   result = ReadValue(name, &buffer[0], &size, NULL);
-  if (FAILED(result) || size == 0)
+  if (result != ERROR_SUCCESS || size == 0)
     return result;
 
   // Parse the double-null-terminated list of strings.
@@ -569,7 +569,7 @@
     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_);
+        reinterpret_cast<BYTE*>(value_.data()), &value_size_);
 
     if (result == ERROR_MORE_DATA) {
       // Registry key names are limited to 255 characters and fit within
@@ -585,7 +585,7 @@
       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_);
+          reinterpret_cast<BYTE*>(value_.data()), &value_size_);
     }
 
     if (result == ERROR_SUCCESS) {
diff --git a/base/win/registry.h b/base/win/registry.h
index c3e015b..83f354d 100644
--- a/base/win/registry.h
+++ b/base/win/registry.h
@@ -11,7 +11,6 @@
 
 #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"
 
@@ -180,7 +179,7 @@
   void operator++();
 
   const wchar_t* Name() const { return name_.c_str(); }
-  const wchar_t* Value() const { return vector_as_array(&value_); }
+  const wchar_t* Value() const { return value_.data(); }
   // ValueSize() is in bytes.
   DWORD ValueSize() const { return value_size_; }
   DWORD Type() const { return type_; }
diff --git a/base/win/scoped_bstr.cc b/base/win/scoped_bstr.cc
index 63ade0c..298318d 100644
--- a/base/win/scoped_bstr.cc
+++ b/base/win/scoped_bstr.cc
@@ -14,7 +14,7 @@
 }
 
 ScopedBstr::~ScopedBstr() {
-  COMPILE_ASSERT(sizeof(ScopedBstr) == sizeof(BSTR), ScopedBstrSize);
+  static_assert(sizeof(ScopedBstr) == sizeof(BSTR), "ScopedBstrSize");
   SysFreeString(bstr_);
 }
 
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
index 373c0c3..5ce60e2 100644
--- a/base/win/scoped_comptr.h
+++ b/base/win/scoped_comptr.h
@@ -43,8 +43,9 @@
   ~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);
+    static_assert(
+        sizeof(ScopedComPtr<Interface, interface_id>) == sizeof(Interface*),
+        "ScopedComPtrSize");
   }
 
   // Explicit Release() of the held object.  Useful for reuse of the
@@ -52,24 +53,24 @@
   // 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;
+    if (this->ptr_ != NULL) {
+      this->ptr_->Release();
+      this->ptr_ = NULL;
     }
   }
 
   // Sets the internal pointer to NULL and returns the held object without
   // releasing the reference.
   Interface* Detach() {
-    Interface* p = ptr_;
-    ptr_ = NULL;
+    Interface* p = this->ptr_;
+    this->ptr_ = NULL;
     return p;
   }
 
   // Accepts an interface pointer that has already been addref-ed.
   void Attach(Interface* p) {
-    DCHECK(!ptr_);
-    ptr_ = p;
+    DCHECK(!this->ptr_);
+    this->ptr_ = p;
   }
 
   // Retrieves the pointer address.
@@ -77,8 +78,8 @@
   // 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_;
+    DCHECK(!this->ptr_) << "Object leak. Pointer must be NULL";
+    return &this->ptr_;
   }
 
   // A convenience for whenever a void pointer is needed as an out argument.
@@ -89,18 +90,18 @@
   template <class Query>
   HRESULT QueryInterface(Query** p) {
     DCHECK(p != NULL);
-    DCHECK(ptr_ != NULL);
+    DCHECK(this->ptr_ != NULL);
     // IUnknown already has a template version of QueryInterface
     // so the iid parameter is implicit here. The only thing this
     // function adds are the DCHECKs.
-    return ptr_->QueryInterface(p);
+    return this->ptr_->QueryInterface(p);
   }
 
   // QI for times when the IID is not associated with the type.
   HRESULT QueryInterface(const IID& iid, void** obj) {
     DCHECK(obj != NULL);
-    DCHECK(ptr_ != NULL);
-    return ptr_->QueryInterface(iid, obj);
+    DCHECK(this->ptr_ != NULL);
+    return this->ptr_->QueryInterface(iid, obj);
   }
 
   // Queries |other| for the interface this object wraps and returns the
@@ -113,18 +114,18 @@
   // Convenience wrapper around CoCreateInstance
   HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
                          DWORD context = CLSCTX_ALL) {
-    DCHECK(!ptr_);
+    DCHECK(!this->ptr_);
     HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
-                                    reinterpret_cast<void**>(&ptr_));
+                                    reinterpret_cast<void**>(&this->ptr_));
     return hr;
   }
 
   // Checks if the identity of |other| and this object is the same.
   bool IsSameObject(IUnknown* other) {
-    if (!other && !ptr_)
+    if (!other && !this->ptr_)
       return true;
 
-    if (!other || !ptr_)
+    if (!other || !this->ptr_)
       return false;
 
     ScopedComPtr<IUnknown> my_identity;
@@ -147,8 +148,8 @@
   // 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_);
+    DCHECK(this->ptr_ != NULL);
+    return reinterpret_cast<BlockIUnknownMethods*>(this->ptr_);
   }
 
   // Pull in operator=() from the parent class.
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc
index d38752d..23090b0 100644
--- a/base/win/scoped_comptr_unittest.cc
+++ b/base/win/scoped_comptr_unittest.cc
@@ -25,8 +25,10 @@
 };
 
 extern const IID dummy_iid;
-const IID dummy_iid = { 0x12345678u, 0x1234u, 0x5678u, 01, 23, 45, 67, 89,
-                        01, 23, 45 };
+const IID dummy_iid = {0x12345678u,
+                       0x1234u,
+                       0x5678u,
+                       {01, 23, 45, 67, 89, 01, 23, 45}};
 
 }  // namespace
 
diff --git a/base/win/scoped_handle.cc b/base/win/scoped_handle.cc
index ce944e4..2ebef32 100644
--- a/base/win/scoped_handle.cc
+++ b/base/win/scoped_handle.cc
@@ -152,12 +152,6 @@
   if (!enabled_)
     return;
 
-  // Idea here is to make our handles non-closable until we close it ourselves.
-  // Handles provided could be totally fabricated especially through our
-  // unittest, we are ignoring that for now by not checking return value.
-  ::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE,
-                         HANDLE_FLAG_PROTECT_FROM_CLOSE);
-
   // Grab the thread id before the lock.
   DWORD thread_id = GetCurrentThreadId();
 
@@ -178,15 +172,6 @@
   if (!enabled_)
     return;
 
-  // We expect handle to be protected till this point.
-  DWORD flags = 0;
-  if (::GetHandleInformation(handle, &flags)) {
-    CHECK_NE(0U, (flags & HANDLE_FLAG_PROTECT_FROM_CLOSE));
-
-    // Unprotect handle so that it could be closed.
-    ::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
-  }
-
   AutoNativeLock lock(*lock_);
   HandleMap::iterator i = map_.find(handle);
   if (i == map_.end())
diff --git a/base/win/scoped_handle.h b/base/win/scoped_handle.h
index 97fd7a5..3e8a748 100644
--- a/base/win/scoped_handle.h
+++ b/base/win/scoped_handle.h
@@ -27,12 +27,16 @@
 
 // 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:
+// the ScopedFILE class with two additions:
 //   - IsValid() method can tolerate multiple invalid handle values such as NULL
 //     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
+//   - Set() (and the constructors and assignment operators that call it)
+//     preserve the Windows LastError code. This ensures that GetLastError() can
+//     be called after stashing a handle in a GenericScopedHandle object. Doing
+//     this explicitly is necessary because of bug 528394 and VC++ 2015.
 template <class Traits, class Verifier>
 class GenericScopedHandle {
-  MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
+  MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle)
 
  public:
   typedef typename Traits::Handle Handle;
@@ -43,9 +47,9 @@
     Set(handle);
   }
 
-  // Move constructor for C++03 move emulation of this type.
-  GenericScopedHandle(RValue other) : handle_(Traits::NullHandle()) {
-    Set(other.object->Take());
+  GenericScopedHandle(GenericScopedHandle&& other)
+      : handle_(Traits::NullHandle()) {
+    Set(other.Take());
   }
 
   ~GenericScopedHandle() {
@@ -56,16 +60,16 @@
     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());
-    }
+  GenericScopedHandle& operator=(GenericScopedHandle&& other) {
+    DCHECK_NE(this, &other);
+    Set(other.Take());
     return *this;
   }
 
   void Set(Handle handle) {
     if (handle_ != handle) {
+      // Preserve old LastError to avoid bug 528394.
+      auto last_error = ::GetLastError();
       Close();
 
       if (Traits::IsHandleValid(handle)) {
@@ -73,6 +77,7 @@
         Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
                                 tracked_objects::GetProgramCounter());
       }
+      ::SetLastError(last_error);
     }
   }
 
diff --git a/base/win/scoped_handle_unittest.cc b/base/win/scoped_handle_unittest.cc
new file mode 100644
index 0000000..b573b66
--- /dev/null
+++ b/base/win/scoped_handle_unittest.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 "base/win/scoped_handle.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ScopedHandleTest, ScopedHandle) {
+  // Any illegal error code will do. We just need to test that it is preserved
+  // by ScopedHandle to avoid bug 528394.
+  const DWORD magic_error = 0x12345678;
+
+  HANDLE handle = ::CreateMutex(nullptr, FALSE, nullptr);
+  // Call SetLastError after creating the handle.
+  ::SetLastError(magic_error);
+  base::win::ScopedHandle handle_holder(handle);
+  EXPECT_EQ(magic_error, ::GetLastError());
+
+  // Create a new handle and then set LastError again.
+  handle = ::CreateMutex(nullptr, FALSE, nullptr);
+  ::SetLastError(magic_error);
+  handle_holder.Set(handle);
+  EXPECT_EQ(magic_error, ::GetLastError());
+
+  // Create a new handle and then set LastError again.
+  handle = ::CreateMutex(nullptr, FALSE, nullptr);
+  base::win::ScopedHandle handle_source(handle);
+  ::SetLastError(magic_error);
+  handle_holder = handle_source.Pass();
+  EXPECT_EQ(magic_error, ::GetLastError());
+}
diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc
index f57ab93..4a1ad90 100644
--- a/base/win/scoped_variant.cc
+++ b/base/win/scoped_variant.cc
@@ -9,10 +9,10 @@
 namespace win {
 
 // Global, const instance of an empty variant.
-const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY };
+const VARIANT ScopedVariant::kEmptyVariant = {{{VT_EMPTY}}};
 
 ScopedVariant::~ScopedVariant() {
-  COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize);
+  static_assert(sizeof(ScopedVariant) == sizeof(VARIANT), "ScopedVariantSize");
   ::VariantClear(&var_);
 }
 
@@ -82,7 +82,7 @@
 }
 
 VARIANT ScopedVariant::Copy() const {
-  VARIANT ret = { VT_EMPTY };
+  VARIANT ret = {{{VT_EMPTY}}};
   ::VariantCopy(&ret, &var_);
   return ret;
 }
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
index f8b2182..ccfa2f5 100644
--- a/base/win/shortcut.cc
+++ b/base/win/shortcut.cc
@@ -314,27 +314,31 @@
   return true;
 }
 
-bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
+bool CanPinShortcutToTaskbar() {
+  // "Pin to taskbar" appeared in Windows 7 and stopped being supported in
+  // Windows 10.
+  return GetVersion() >= VERSION_WIN7 && GetVersion() < VERSION_WIN10;
+}
+
+bool PinShortcutToTaskbar(const FilePath& shortcut) {
   base::ThreadRestrictions::AssertIOAllowed();
+  DCHECK(CanPinShortcutToTaskbar());
 
-  // "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));
+  intptr_t result = reinterpret_cast<intptr_t>(ShellExecute(
+      NULL, L"taskbarpin", shortcut.value().c_str(), NULL, NULL, 0));
   return result > 32;
 }
 
-bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
+bool UnpinShortcutFromTaskbar(const FilePath& shortcut) {
   base::ThreadRestrictions::AssertIOAllowed();
 
-  // "Unpin from taskbar" is only supported after Win7.
+  // "Unpin from taskbar" is only supported after Win7. It is possible to remove
+  // a shortcut pinned by a user on Windows 10+.
   if (GetVersion() < VERSION_WIN7)
     return false;
 
-  intptr_t result = reinterpret_cast<intptr_t>(
-      ShellExecute(NULL, L"taskbarunpin", shortcut, NULL, NULL, 0));
+  intptr_t result = reinterpret_cast<intptr_t>(ShellExecute(
+      NULL, L"taskbarunpin", shortcut.value().c_str(), NULL, NULL, 0));
   return result > 32;
 }
 
diff --git a/base/win/shortcut.h b/base/win/shortcut.h
index 6f7d10c..a41cc3d 100644
--- a/base/win/shortcut.h
+++ b/base/win/shortcut.h
@@ -152,15 +152,19 @@
                                  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);
+// Pin to taskbar is only supported on Windows 7 and Windows 8. Returns true on
+// those platforms.
+BASE_EXPORT bool CanPinShortcutToTaskbar();
 
-// Unpins a shortcut from the Windows 7 taskbar. The shortcut must exist and
+// Pins a shortcut to the taskbar on Windows 7 and 8. 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 PinShortcutToTaskbar(const FilePath& 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);
+BASE_EXPORT bool UnpinShortcutFromTaskbar(const FilePath& shortcut);
 
 }  // namespace win
 }  // namespace base
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index c5b06c4..93ec543 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -19,11 +19,14 @@
 #include <signal.h>
 #include <stdlib.h>
 
+#include "base/base_switches.h"
+#include "base/command_line.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 "base/threading/thread_restrictions.h"
 #include "base/win/metro.h"
 #include "base/win/registry.h"
@@ -32,13 +35,16 @@
 #include "base/win/scoped_propvariant.h"
 #include "base/win/windows_version.h"
 
+namespace base {
+namespace win {
+
 namespace {
 
 // Sets the value of |property_key| to |property_value| in |property_store|.
 bool SetPropVariantValueForPropertyStore(
     IPropertyStore* property_store,
     const PROPERTYKEY& property_key,
-    const base::win::ScopedPropVariant& property_value) {
+    const ScopedPropVariant& property_value) {
   DCHECK(property_store);
 
   HRESULT result = property_store->SetValue(property_key, property_value.get());
@@ -48,31 +54,94 @@
 }
 
 void __cdecl ForceCrashOnSigAbort(int) {
-  *((int*)0) = 0x1337;
+  *((volatile int*)0) = 0x1337;
 }
 
+typedef decltype(GetProcessMitigationPolicy)* GetProcessMitigationPolicyType;
+
+class LazyIsUser32AndGdi32Available {
+ public:
+  LazyIsUser32AndGdi32Available() : value_(!IsWin32kSyscallsDisabled()) {}
+
+  ~LazyIsUser32AndGdi32Available() {}
+
+  bool value() { return value_; }
+
+ private:
+  static bool IsWin32kSyscallsDisabled() {
+    // Can't disable win32k prior to windows 8.
+    if (base::win::GetVersion() < base::win::VERSION_WIN8)
+      return false;
+
+    GetProcessMitigationPolicyType get_process_mitigation_policy_func =
+        reinterpret_cast<GetProcessMitigationPolicyType>(GetProcAddress(
+            GetModuleHandle(L"kernel32.dll"), "GetProcessMitigationPolicy"));
+
+    if (!get_process_mitigation_policy_func)
+      return false;
+
+    PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
+    if (get_process_mitigation_policy_func(GetCurrentProcess(),
+                                           ProcessSystemCallDisablePolicy,
+                                           &policy, sizeof(policy))) {
+      return policy.DisallowWin32kSystemCalls != 0;
+    }
+
+    return false;
+  }
+
+  const bool value_;
+
+  DISALLOW_COPY_AND_ASSIGN(LazyIsUser32AndGdi32Available);
+};
+
 const wchar_t kWindows8OSKRegPath[] =
     L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}"
     L"\\LocalServer32";
 
+}  // namespace
+
 // 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() {
+bool IsKeyboardPresentOnSlate(std::string* reason) {
+  bool result = false;
+
+  if (GetVersion() < VERSION_WIN7) {
+    *reason = "Detection not supported";
+    return false;
+  }
+
   // This function is only supported for Windows 8 and up.
-  DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN8);
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableUsbKeyboardDetect)) {
+    if (reason)
+      *reason = "Detection disabled";
+    return false;
+  }
 
   // This function should be only invoked for machines with touch screens.
   if ((GetSystemMetrics(SM_DIGITIZER) & NID_INTEGRATED_TOUCH)
         != NID_INTEGRATED_TOUCH) {
-    return true;
+    if (reason) {
+      *reason += "NID_INTEGRATED_TOUCH\n";
+      result = true;
+    } else {
+      return true;
+    }
   }
 
   // If the device is docked, the user is treating the device as a PC.
-  if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
-    return true;
+  if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) {
+    if (reason) {
+      *reason += "SM_SYSTEMDOCKED\n";
+      result = true;
+    } else {
+      return true;
+    }
+  }
 
   // To determine whether a keyboard is present on the device, we do the
   // following:-
@@ -103,7 +172,13 @@
       // 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;
+      if (reason) {
+        *reason += (auto_rotation_state & AR_NOSENSOR) ? "AR_NOSENSOR\n" :
+                                                         "AR_NOT_SUPPORTED\n";
+        result = true;
+      } else {
+        return true;
+      }
     }
   }
 
@@ -114,8 +189,15 @@
   POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
 
   if (((role == PlatformRoleMobile) || (role == PlatformRoleSlate)) &&
-       (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0))
-    return false;
+       (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0)) {
+      if (reason) {
+        *reason += (role == PlatformRoleMobile) ? "PlatformRoleMobile\n" :
+                                                  "PlatformRoleSlate\n";
+        // Don't change result here if it's already true.
+      } else {
+        return false;
+      }
+  }
 
   const GUID KEYBOARD_CLASS_GUID =
       { 0x4D36E96B, 0xE325,  0x11CE,
@@ -124,13 +206,15 @@
   // 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;
+  if (device_info == INVALID_HANDLE_VALUE) {
+    if (reason)
+      *reason += "No keyboard info\n";
+    return result;
+  }
 
   // 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);
@@ -146,23 +230,24 @@
     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++;
+      if (StartsWith(device_id, L"ACPI", CompareCase::INSENSITIVE_ASCII) ||
+          StartsWith(device_id, L"HID\\VID", CompareCase::INSENSITIVE_ASCII)) {
+        if (reason) {
+          *reason += "device: ";
+          *reason += WideToUTF8(device_id);
+          *reason += '\n';
+        }
+        // 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.
+        result = true;
       }
     }
   }
-  // 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;
+  return result;
 }
 
-}  // namespace
-
-namespace base {
-namespace win {
-
 static bool g_crash_on_process_detach = false;
 
 void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics) {
@@ -181,7 +266,7 @@
   HANDLE token = NULL;
   if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
     return false;
-  base::win::ScopedHandle token_scoped(token);
+  ScopedHandle token_scoped(token);
 
   DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
   scoped_ptr<BYTE[]> user_bytes(new BYTE[size]);
@@ -205,32 +290,15 @@
   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;
+  ThreadRestrictions::ScopedAllowIO allow_io;
 
-  base::win::RegKey key(HKEY_LOCAL_MACHINE,
-      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
-      KEY_READ);
+  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;
@@ -284,20 +352,20 @@
 
 bool AddCommandToAutoRun(HKEY root_key, const string16& name,
                          const string16& command) {
-  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  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);
+  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);
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
   return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS);
 }
 
@@ -326,8 +394,8 @@
   if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0)
     return false;
 
-  base::win::Version version = base::win::GetVersion();
-  if (version == base::win::VERSION_XP)
+  Version version = GetVersion();
+  if (version == VERSION_XP)
     return (GetSystemMetrics(SM_TABLETPC) != 0);
 
   // If the device is docked, the user is treating the device as a PC.
@@ -339,7 +407,7 @@
   POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
   bool mobile_power_profile = (role == PlatformRoleMobile);
   bool slate_power_profile = false;
-  if (version >= base::win::VERSION_WIN8)
+  if (version >= VERSION_WIN8)
     slate_power_profile = (role == PlatformRoleSlate);
 
   if (mobile_power_profile || slate_power_profile)
@@ -349,14 +417,13 @@
 }
 
 bool DisplayVirtualKeyboard() {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+  if (GetVersion() < VERSION_WIN8)
     return false;
 
-  if (IsKeyboardPresentOnSlate())
+  if (IsKeyboardPresentOnSlate(nullptr))
     return false;
 
-  static base::LazyInstance<string16>::Leaky osk_path =
-      LAZY_INSTANCE_INITIALIZER;
+  static LazyInstance<string16>::Leaky osk_path = LAZY_INSTANCE_INITIALIZER;
 
   if (osk_path.Get().empty()) {
     // We need to launch TabTip.exe from the location specified under the
@@ -367,9 +434,8 @@
     // 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);
+    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),
@@ -410,7 +476,7 @@
         common_program_files_path = common_program_files_wow6432.get();
         DCHECK(!common_program_files_path.empty());
       } else {
-        base::win::ScopedCoMem<wchar_t> common_program_files;
+        ScopedCoMem<wchar_t> common_program_files;
         if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL,
                                         &common_program_files))) {
           return false;
@@ -432,7 +498,7 @@
 }
 
 bool DismissVirtualKeyboard() {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+  if (GetVersion() < VERSION_WIN8)
     return false;
 
   // We dismiss the virtual keyboard by generating the ESC keystroke
@@ -474,23 +540,29 @@
 }
 
 bool MaybeHasSHA256Support() {
-  const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
+  const OSInfo* os_info = OSInfo::GetInstance();
 
-  if (os_info->version() == base::win::VERSION_PRE_XP)
+  if (os_info->version() == VERSION_PRE_XP)
     return false;  // Too old to have it and this OS is not supported anyway.
 
-  if (os_info->version() == base::win::VERSION_XP)
+  if (os_info->version() == VERSION_XP)
     return os_info->service_pack().major >= 3;  // Windows XP SP3 has it.
 
   // Assume it is missing in this case, although it may not be. This category
   // includes Windows XP x64, and Windows Server, where a hotfix could be
   // deployed.
-  if (os_info->version() == base::win::VERSION_SERVER_2003)
+  if (os_info->version() == VERSION_SERVER_2003)
     return false;
 
-  DCHECK(os_info->version() >= base::win::VERSION_VISTA);
+  DCHECK(os_info->version() >= VERSION_VISTA);
   return true;  // New enough to have SHA-256 support.
 }
 
+bool IsUser32AndGdi32Available() {
+  static base::LazyInstance<LazyIsUser32AndGdi32Available>::Leaky available =
+      LAZY_INSTANCE_INITIALIZER;
+  return available.Get().value();
+}
+
 }  // namespace win
 }  // namespace base
diff --git a/base/win/win_util.h b/base/win/win_util.h
index 8513f62..384db80 100644
--- a/base/win/win_util.h
+++ b/base/win/win_util.h
@@ -61,20 +61,6 @@
 // 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
@@ -132,6 +118,11 @@
 // insight into how users use Chrome.
 BASE_EXPORT bool IsTabletDevice();
 
+// A slate is a touch device that may have a keyboard attached. This function
+// returns true if a keyboard is attached and optionally will set the reason
+// parameter to the detection method that was used to detect the keyboard.
+BASE_EXPORT bool IsKeyboardPresentOnSlate(std::string* reason);
+
 // 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).
@@ -161,6 +152,13 @@
 // run-time detection of this capability.
 BASE_EXPORT bool MaybeHasSHA256Support();
 
+// Returns true if the current process can make USER32 or GDI32 calls such as
+// CreateWindow and CreateDC. Windows 8 and above allow the kernel component
+// of these calls to be disabled which can cause undefined behaviour such as
+// crashes. This function can be used to guard areas of code using these calls
+// and provide a fallback path if necessary.
+BASE_EXPORT bool IsUser32AndGdi32Available();
+
 }  // namespace win
 }  // namespace base
 
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc
index fc2def3..35cdbb3 100644
--- a/base/win/windows_version.cc
+++ b/base/win/windows_version.cc
@@ -73,7 +73,7 @@
   service_pack_.major = version_info.wServicePackMajor;
   service_pack_.minor = version_info.wServicePackMinor;
 
-  SYSTEM_INFO system_info = { 0 };
+  SYSTEM_INFO system_info = {};
   ::GetNativeSystemInfo(&system_info);
   switch (system_info.wProcessorArchitecture) {
     case PROCESSOR_ARCHITECTURE_INTEL: architecture_ = X86_ARCHITECTURE; break;
diff --git a/build/OWNERS b/build/OWNERS
index 17d067c..d0422bc 100644
--- a/build/OWNERS
+++ b/build/OWNERS
@@ -1,5 +1,6 @@
-cjhopman@chromium.org
+agrieve@chromium.org
 dpranke@chromium.org
+jbudorick@chromium.org
 jochen@chromium.org
 scottmg@chromium.org
 thakis@chromium.org
diff --git a/build/all.gyp b/build/all.gyp
index 4d79a84..48e4482 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -85,17 +85,15 @@
               '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',
+                '../android_webview/android_webview_shell.gyp:system_webview_shell_apk',
+                '../chrome/android/chrome_apk.gyp:chrome_public_apk',
+                '../chrome/android/chrome_apk.gyp:chrome_sync_shell_apk',
               ],
             }],
-            ['target_arch == "arm" or target_arch == "arm64"', {
+            # TODO: Enable packed relocations for x64. See: b/20532404
+            ['target_arch != "x64"', {
               'dependencies': [
-                # The relocation packer only works on ARM or ARM64.
-                '../tools/relocation_packer/relocation_packer.gyp:relocation_packer_unittests#host',
+                '../third_party/android_platform/relocation_packer.gyp:android_relocation_packer_unittests#host',
               ],
             }],
           ],
@@ -110,7 +108,6 @@
           '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:*',
@@ -162,7 +159,7 @@
             '../device/device_tests.gyp:*',
           ],
         }],
-        ['use_openssl==0 and (OS=="mac" or OS=="ios" or OS=="win")', {
+        ['use_openssl==0 and OS=="ios"', {
           'dependencies': [
             '../third_party/nss/nss.gyp:*',
            ],
@@ -376,10 +373,9 @@
         }],
         ['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/chrome.gyp:setup_unittests',
             # ../chrome/test/mini_installer requires mini_installer.
             '../chrome/installer/mini_installer.gyp:mini_installer',
             '../chrome_elf/chrome_elf.gyp:chrome_elf_unittests',
@@ -476,7 +472,7 @@
         }],
         ['use_aura==1 or toolkit_views==1', {
           'dependencies': [
-            '../ui/events/events.gyp:events_unittests',
+            '../ui/events/events_unittests.gyp:events_unittests',
           ],
         }],
         ['use_ash==1', {
@@ -489,17 +485,9 @@
             '../components/nacl.gyp:nacl_loader_unittests',
           ],
         }],
-        ['disable_nacl==0 and disable_nacl_untrusted==0 and OS=="linux"', {
+        ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
           'dependencies': [
-            '../components/nacl_nonsfi.gyp:nacl_helper_nonsfi_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',
+            '../components/nacl.gyp:nacl_helper_nonsfi_unittests',
           ],
         }],
       ],
@@ -507,7 +495,7 @@
   ],
   'conditions': [
     # TODO(GYP): make gn_migration.gypi work unconditionally.
-    ['OS=="mac" or OS=="win" or (OS=="linux" and target_arch=="x64" and chromecast==0)', {
+    ['OS=="mac" or OS=="win" or (OS=="android" and chromecast==0) or (OS=="linux" and target_arch=="x64" and chromecast==0)', {
       'includes': [
         'gn_migration.gypi',
       ],
@@ -526,16 +514,18 @@
                 '../content/content_shell_and_tests.gyp:content_shell_apk',
                 '../breakpad/breakpad.gyp:dump_syms#host',
                 '../breakpad/breakpad.gyp:minidump_stackwalk#host',
+                '../tools/imagediff/image_diff.gyp:image_diff#host',
               ],
             }, {  # OS!="android"
               'dependencies': [
                 '../content/content_shell_and_tests.gyp:content_shell',
+                '../tools/imagediff/image_diff.gyp:image_diff',
               ],
             }],
             ['OS=="win"', {
               'dependencies': [
+                '../components/test_runner/test_runner.gyp:layout_test_helper',
                 '../content/content_shell_and_tests.gyp:content_shell_crash_service',
-                '../content/content_shell_and_tests.gyp:layout_test_helper',
               ],
             }],
             ['OS!="win" and OS!="android"', {
@@ -545,8 +535,8 @@
             }],
             ['OS=="mac"', {
               'dependencies': [
+                '../components/test_runner/test_runner.gyp:layout_test_helper',
                 '../breakpad/breakpad.gyp:dump_syms#host',
-                '../content/content_shell_and_tests.gyp:layout_test_helper',
               ],
             }],
             ['OS=="linux"', {
@@ -790,9 +780,7 @@
       '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.
+          # until the full set supported.
           #
           # WARNING:
           # Do not add targets here without communicating the implications
@@ -810,7 +798,6 @@
             '../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',
@@ -843,7 +830,7 @@
             '../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/events/events_unittests.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',
@@ -861,14 +848,13 @@
             '../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/events/events_unittests.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',
@@ -881,17 +867,14 @@
                 # 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',
+                '../android_webview/android_webview_shell.gyp:system_webview_shell_layout_test_apk',
+                '../android_webview/android_webview_shell.gyp:system_webview_shell_page_cycler_apk',
+                '../chrome/android/chrome_apk.gyp:chrome_public_test_apk',
+                '../chrome/android/chrome_apk.gyp:chrome_sync_shell_test_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',
+                '../third_party/custom_tabs_client/custom_tabs_client.gyp:custom_tabs_client_example_apk',
               ],
             }],
           ],
@@ -905,8 +888,6 @@
             '../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
@@ -1077,6 +1058,7 @@
             '../chrome/chrome.gyp:installer_util_unittests',
             '../chrome/chrome.gyp:interactive_ui_tests',
             '../chrome/chrome.gyp:performance_browser_tests',
+            '../chrome/chrome.gyp:setup_unittests',
             '../chrome/chrome.gyp:sync_integration_tests',
             '../chrome/chrome.gyp:unit_tests',
             '../cloud_print/cloud_print.gyp:cloud_print_unittests',
@@ -1108,7 +1090,7 @@
             '../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/events/events_unittests.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',
@@ -1151,16 +1133,15 @@
           'target_name': 'chromium_builder_lkgr_drmemory_win',
           'type': 'none',
           'dependencies': [
+            '../components/test_runner/test_runner.gyp:layout_test_helper',
             '../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',
@@ -1169,14 +1150,15 @@
             '../chrome/chrome.gyp:chrome_app_unittests',
             '../chrome/chrome.gyp:chromedriver_unittests',
             '../chrome/chrome.gyp:installer_util_unittests',
+            '../chrome/chrome.gyp:setup_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',
+            '../components/test_runner/test_runner.gyp:layout_test_helper',
             '../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',
@@ -1213,7 +1195,7 @@
             '../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/events/events_unittests.gyp:events_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
             '../ui/gl/gl_tests.gyp:gl_unittests',
             '../ui/keyboard/keyboard.gyp:keyboard_unittests',
@@ -1229,7 +1211,6 @@
               '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',
@@ -1257,15 +1238,14 @@
               'target_name': 'chrome_official_builder',
               'type': 'none',
               'dependencies': [
-	        'chrome_official_builder_no_unittests',
+                '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',
+                '../net/net.gyp:net_unittests',
                 '../printing/printing.gyp:printing_unittests',
                 '../sql/sql.gyp:sql_unittests',
                 '../sync/sync.gyp:sync_unit_tests',
@@ -1281,6 +1261,36 @@
         }], # branding=="Chrome"
        ], # conditions
     }], # OS="win"
+    ['chromeos==1', {
+      'targets': [
+        {
+          'target_name': 'chromiumos_preflight',
+          'type': 'none',
+          'dependencies': [
+            '../breakpad/breakpad.gyp:minidump_stackwalk',
+            '../chrome/chrome.gyp:chrome',
+            '../chrome/chrome.gyp:chromedriver',
+            '../content/content_shell_and_tests.gyp:video_decode_accelerator_unittest',
+            '../content/content_shell_and_tests.gyp:video_encode_accelerator_unittest',
+            '../media/media.gyp:media_unittests',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_video_decode',
+            '../sandbox/sandbox.gyp:chrome_sandbox',
+            '../sandbox/sandbox.gyp:sandbox_linux_unittests',
+            '../third_party/mesa/mesa.gyp:osmesa',
+            '../tools/telemetry/telemetry.gyp:bitmaptools#host',
+            '../tools/perf/clear_system_cache/clear_system_cache.gyp:clear_system_cache',
+          ],
+          'conditions': [
+            ['disable_nacl==0', {
+              'dependencies': [
+                '../components/nacl.gyp:nacl_helper',
+                '../native_client/src/trusted/service_runtime/linux/nacl_bootstrap.gyp:nacl_helper_bootstrap',
+              ],
+            }],
+          ],
+        },
+      ],  # targets
+    }], # "chromeos==1"
     ['use_aura==1', {
       'targets': [
         {
@@ -1325,7 +1335,7 @@
             }],
             ['use_ash==1', {
               'dependencies': [
-                '../ash/ash.gyp:ash_shell',
+                '../ash/ash.gyp:ash_shell_with_content',
                 '../ash/ash.gyp:ash_unittests',
               ],
             }],
@@ -1396,11 +1406,22 @@
           'target_name': 'chromoting_swarm_tests',
           'type': 'none',
           'dependencies': [
-            '../testing/chromoting/integration_tests.gyp:chromoting_integration_tests_run',
+            '../testing/chromoting/integration_tests.gyp:*',
           ],
         }, # target_name: chromoting_swarm_tests
       ]
     }],
+    ['archive_media_router_tests==1', {
+      'targets': [
+        {
+          'target_name': 'media_router_swarming_tests',
+          'type': 'none',
+          'dependencies': [
+            '../chrome/test/media_router/e2e_tests.gyp:media_router_e2e_tests_run',
+          ],
+        }, # target_name: media_router_swarming_tests
+      ]
+    }],
     ['OS=="mac" and toolkit_views==1', {
       'targets': [
         {
diff --git a/build/android/AndroidManifest.xml b/build/android/AndroidManifest.xml
index f27872e..e1e2904 100644
--- a/build/android/AndroidManifest.xml
+++ b/build/android/AndroidManifest.xml
@@ -15,6 +15,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="dummy.package">
 
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="22" />
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
 
 </manifest>
diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn
new file mode 100644
index 0000000..e45cf2d
--- /dev/null
+++ b/build/android/BUILD.gn
@@ -0,0 +1,77 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+import("//third_party/ijar/ijar.gni")
+
+sun_tools_jar_path = "$root_gen_dir/sun_tools_jar/tools.jar"
+
+action("find_sun_tools_jar") {
+  script = "//build/android/gyp/find_sun_tools_jar.py"
+  depfile = "$target_gen_dir/$target_name.d"
+  outputs = [
+    depfile,
+    sun_tools_jar_path,
+  ]
+  args = [
+    "--depfile",
+    rebase_path(depfile, root_build_dir),
+    "--output",
+    rebase_path(sun_tools_jar_path, root_build_dir),
+  ]
+}
+
+java_prebuilt("sun_tools_java") {
+  jar_path = sun_tools_jar_path
+  jar_dep = ":find_sun_tools_jar"
+}
+
+generate_interface_jar("android_ijar") {
+  input_jar = android_sdk_jar
+  output_jar = "$root_out_dir/lib.java/android.interface.jar"
+}
+
+# Copy to the lib.unstripped directory so that gdb can easily find it.
+copy("cpplib_unstripped") {
+  _soname = "libc++_shared.so"
+  sources = [
+    "${android_libcpp_root}/libs/${android_app_abi}/${_soname}",
+  ]
+  outputs = [
+    "${root_out_dir}/lib.unstripped/${_soname}",
+  ]
+}
+
+action("cpplib_stripped") {
+  _strip_bin = "${android_tool_prefix}strip"
+  _soname = "libc++_shared.so"
+  _input_so = "${root_out_dir}/lib.unstripped/${_soname}"
+  _output_so = "${root_shlib_dir}/${_soname}"
+
+  deps = [
+    ":cpplib_unstripped",
+  ]
+
+  script = "//build/gn_run_binary.py"
+  inputs = [
+    _strip_bin,
+  ]
+  sources = [
+    _input_so,
+  ]
+  outputs = [
+    _output_so,
+  ]
+
+  _rebased_strip_bin = rebase_path(_strip_bin, root_out_dir)
+  _rebased_input_so = rebase_path(_input_so, root_out_dir)
+  _rebased_output_so = rebase_path(_output_so, root_out_dir)
+  args = [
+    _rebased_strip_bin,
+    "--strip-unneeded",
+    "-o",
+    _rebased_output_so,
+    _rebased_input_so,
+  ]
+}
diff --git a/build/android/OWNERS b/build/android/OWNERS
index 9a5d270..09f8997 100644
--- a/build/android/OWNERS
+++ b/build/android/OWNERS
@@ -1,3 +1,6 @@
 jbudorick@chromium.org
 klundberg@chromium.org
+mikecase@chromium.org
 pasko@chromium.org
+perezju@chromium.org
+rnephew@chromium.org
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
index 6e0a3de..5e4c988 100644
--- a/build/android/PRESUBMIT.py
+++ b/build/android/PRESUBMIT.py
@@ -16,17 +16,22 @@
     """Returns a path relative to presubmit directory."""
     return input_api.os_path.join(input_api.PresubmitLocalPath(), *dirs)
 
+  build_pys = [
+      r'gyp/.*\.py$',
+      r'gn/.*\.py',
+      r'incremental_install/.*\.py',
+  ]
   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')]))
+      pylintrc='pylintrc',
+      # symbols has its own PRESUBMIT.py
+      black_list=build_pys + [r'pylib/symbols/.*\.py$'],
+      extra_paths_list=[J(), J('buildbot')]))
   output.extend(input_api.canned_checks.RunPylint(
       input_api,
       output_api,
-      white_list=[r'gyp/.*\.py$', r'gn/.*\.py'],
+      white_list=build_pys,
       extra_paths_list=[J('gyp'), J('gn')]))
 
   # Disabled due to http://crbug.com/410936
@@ -42,15 +47,21 @@
       input_api,
       output_api,
       unit_tests=[
+          J('.', 'emma_coverage_stats_test.py'),
+          J('devil', 'android', 'fastboot_utils_test.py'),
+          J('devil', 'android', 'battery_utils_test.py'),
+          J('devil', 'android', 'device_utils_test.py'),
+          J('devil', 'android', 'md5sum_test.py'),
+          J('devil', 'android', 'logcat_monitor_test.py'),
+          J('devil', 'utils', 'cmd_helper_test.py'),
+          J('devil', 'utils', 'timeout_retry_unittest.py'),
+          J('gyp', 'util', 'md5_check_test.py'),
+          J('play_services', 'update_test.py'),
           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
diff --git a/build/android/adb_android_webview_command_line b/build/android/adb_android_webview_command_line
index 947cfb1..9075918 100755
--- a/build/android/adb_android_webview_command_line
+++ b/build/android/adb_android_webview_command_line
@@ -13,25 +13,5 @@
 # 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
-
+exec $(dirname $0)/adb_command_line.py --device-path \
+    /data/local/tmp/android-webview-command-line "$@"
diff --git a/build/android/adb_blimp_command_line b/build/android/adb_blimp_command_line
new file mode 100755
index 0000000..1ff3769
--- /dev/null
+++ b/build/android/adb_blimp_command_line
@@ -0,0 +1,17 @@
+#!/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.
+
+# If no flags are given, prints the current Blimp flags.
+#
+# Otherwise, the given flags are used to REPLACE (not modify) the Blimp
+# flags. For example:
+#   adb_blimp_command_line --enable-webgl
+#
+# To remove all Blimp flags, pass an empty string for the flags:
+#   adb_blimp_command_line ""
+
+exec $(dirname $0)/adb_command_line.py --device-path \
+    /data/local/blimp-command-line "$@"
diff --git a/build/android/adb_chrome_public_command_line b/build/android/adb_chrome_public_command_line
new file mode 100755
index 0000000..ac379e8
--- /dev/null
+++ b/build/android/adb_chrome_public_command_line
@@ -0,0 +1,17 @@
+#!/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.
+
+# If no flags are given, prints the current Chrome flags.
+#
+# Otherwise, the given flags are used to REPLACE (not modify) the Chrome
+# flags. For example:
+#   adb_chrome_public_command_line --enable-webgl
+#
+# To remove all Chrome flags, pass an empty string for the flags:
+#   adb_chrome_public_command_line ""
+
+exec $(dirname $0)/adb_command_line.py --device-path \
+    /data/local/chrome-command-line "$@"
diff --git a/build/android/adb_chrome_shell_command_line b/build/android/adb_chrome_shell_command_line
deleted file mode 100755
index 1e2bd38..0000000
--- a/build/android/adb_chrome_shell_command_line
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/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_command_line.py b/build/android/adb_command_line.py
new file mode 100755
index 0000000..fa3a82b
--- /dev/null
+++ b/build/android/adb_command_line.py
@@ -0,0 +1,83 @@
+#!/usr/bin/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.
+
+"""Utility for reading / writing command-line flag files on device(s)."""
+
+import argparse
+import sys
+
+from devil.android import device_utils
+from devil.android import device_errors
+from devil.utils import cmd_helper
+
+
+def main():
+  parser = argparse.ArgumentParser(description=__doc__)
+  parser.usage = '''%(prog)s --device-path PATH [--device SERIAL] [flags...]
+
+No flags: Prints existing command-line file.
+Empty string: Deletes command-line file.
+Otherwise: Writes command-line file.
+
+'''
+  parser.add_argument('-d', '--device', dest='device',
+                      help='Target device for apk to install on.')
+  parser.add_argument('--device-path', required=True,
+                      help='Remote path to flags file.')
+  args, remote_args = parser.parse_known_args()
+
+  as_root = not args.device_path.startswith('/data/local/tmp/')
+
+  if args.device:
+    devices = [device_utils.DeviceUtils(args.device, default_retries=0)]
+  else:
+    devices = device_utils.DeviceUtils.HealthyDevices(default_retries=0)
+    if not devices:
+      raise device_errors.NoDevicesError()
+
+  all_devices = device_utils.DeviceUtils.parallel(devices)
+
+  def print_args():
+    def read_flags(device):
+      try:
+        return device.ReadFile(args.device_path, as_root=as_root)
+      except device_errors.AdbCommandFailedError:
+        return '\n'  # File might not exist.
+
+    descriptions = all_devices.pMap(lambda d: d.build_description).pGet(None)
+    flags = all_devices.pMap(read_flags).pGet(None)
+    for d, desc, flags in zip(devices, descriptions, flags):
+      print '  %s (%s): %s' % (d, desc, flags),
+
+  # No args == print flags.
+  if not remote_args:
+    print 'Existing flags (in %s):' % args.device_path
+    print_args()
+    return 0
+
+  # Empty string arg == delete flags file.
+  if len(remote_args) == 1 and not remote_args[0]:
+    def delete_flags(device):
+      device.RunShellCommand(['rm', '-f', args.device_path], as_root=as_root)
+    all_devices.pMap(delete_flags).pGet(None)
+    print 'Deleted %s' % args.device_path
+    return 0
+
+  # Set flags.
+  quoted_args = ' '.join(cmd_helper.SingleQuote(x) for x in remote_args)
+  flags_str = 'chrome %s' % quoted_args
+
+  def write_flags(device):
+    device.WriteFile(args.device_path, flags_str, as_root=as_root)
+    device.RunShellCommand(['chmod', '0664', args.device_path], as_root=as_root)
+
+  all_devices.pMap(write_flags).pGet(None)
+  print 'Wrote flags to %s' % args.device_path
+  print_args()
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/adb_content_shell_command_line b/build/android/adb_content_shell_command_line
index f3c1d4f..02ef802 100755
--- a/build/android/adb_content_shell_command_line
+++ b/build/android/adb_content_shell_command_line
@@ -13,25 +13,5 @@
 # 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
-
+exec $(dirname $0)/adb_command_line.py --device-path \
+    /data/local/tmp/content-shell-command-line "$@"
diff --git a/build/android/adb_gdb b/build/android/adb_gdb
index 65ec7b2..15320df 100755
--- a/build/android/adb_gdb
+++ b/build/android/adb_gdb
@@ -691,7 +691,7 @@
 package is installed?"
 fi
 
-# Return the timestamp of a given time, as number of seconds since epoch.
+# Return the timestamp of a given file, as number of seconds since epoch.
 # $1: file path
 # Out: file timestamp
 get_file_timestamp () {
@@ -707,12 +707,14 @@
 #
 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.
+  # Make places them under out/$BUILDTYPE/lib.target.
+  # GYP places debug libraries under out/$BUILDTYPE/lib
+  # GN places them under out/$BUILDTYPE/lib.unstripped
   if [ "$1" ]; then
-    SUBDIRS="$1/lib $1/lib.target"
+    SUBDIRS="$1/lib $1/lib.target $1/lib.unstripped"
   else
     SUBDIRS="Release/lib Debug/lib Release/lib.target Debug/lib.target"
+    SUBDIRS+=" Release/lib.unstripped Debug/lib.unstripped"
   fi
   LIST=$TMPDIR/scan-subdirs-$$.txt
   printf "" > "$LIST"
@@ -767,6 +769,7 @@
 
 HOST_FINGERPRINT=
 DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint)
+[[ "$DEVICE_FINGERPRINT" ]] || panic "Failed to get the device fingerprint"
 log "Device build fingerprint: $DEVICE_FINGERPRINT"
 
 # If --pull-libs-dir is not specified, and this is a platform build, look
@@ -794,11 +797,11 @@
 # 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
+  if [ ! -f "$PULL_LIBS_DIR/build.fingerprint" ]; then
     log "Auto-config: --pull-libs  (no cached libraries)"
     PULL_LIBS=true
   else
-    HOST_FINGERPRINT=$(get_build_fingerprint_from "$PULL_LIBS_DIR/build.prop")
+    HOST_FINGERPRINT=$(< "$PULL_LIBS_DIR/build.fingerprint")
     log "Host build fingerprint:   $HOST_FINGERPRINT"
     if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then
       log "Auto-config: --no-pull-libs (fingerprint match)"
@@ -897,7 +900,6 @@
 # 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."
@@ -907,6 +909,8 @@
       panic "Use --su-prefix if the application is not debuggable."
     fi
   fi
+  # Remove the fingerprint file in case pulling one of the libs fails.
+  rm -f "$PULL_LIBS_DIR/build.fingerprint"
   SYSTEM_LIBS=$(echo "$MAPPINGS" | \
       awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' | sort -u)
   for SYSLIB in /system/bin/linker $SYSTEM_LIBS; do
@@ -916,9 +920,8 @@
     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 !?"
+  echo "Writing the device fingerprint"
+  echo "$DEVICE_FINGERPRINT" > "$PULL_LIBS_DIR/build.fingerprint"
 fi
 
 # Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4
@@ -980,9 +983,9 @@
 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) &
+  --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"
diff --git a/build/android/adb_gdb_blimp_client b/build/android/adb_gdb_blimp_client
new file mode 100755
index 0000000..3c2e21d
--- /dev/null
+++ b/build/android/adb_gdb_blimp_client
@@ -0,0 +1,16 @@
+#!/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.
+#
+# Attach to or start a Blimp process and debug it.
+# See --help for details.
+#
+PROGDIR=$(dirname "$0")
+export ADB_GDB_PROGNAME=$(basename "$0")
+export ADB_GDB_ACTIVITY=org.chromium.blimp.BlimpRendererActivity
+"$PROGDIR"/adb_gdb \
+    --program-name=Blimp \
+    --package-name=org.chromium.blimp \
+    "$@"
diff --git a/build/android/adb_gdb_chrome_public b/build/android/adb_gdb_chrome_public
new file mode 100755
index 0000000..4366c83
--- /dev/null
+++ b/build/android/adb_gdb_chrome_public
@@ -0,0 +1,16 @@
+#!/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.
+#
+# Attach to or start a ChromePublic process and debug it.
+# See --help for details.
+#
+PROGDIR=$(dirname "$0")
+export ADB_GDB_PROGNAME=$(basename "$0")
+export ADB_GDB_ACTIVITY=com.google.android.apps.chrome.Main
+"$PROGDIR"/adb_gdb \
+    --program-name=ChromePublic \
+    --package-name=org.chromium.chrome \
+    "$@"
diff --git a/build/android/adb_gdb_chrome_shell b/build/android/adb_gdb_chrome_shell
deleted file mode 100755
index e5c8a30..0000000
--- a/build/android/adb_gdb_chrome_shell
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/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_install_apk.py b/build/android/adb_install_apk.py
index 00bd38e..a816bd4 100755
--- a/build/android/adb_install_apk.py
+++ b/build/android/adb_install_apk.py
@@ -6,84 +6,115 @@
 
 """Utility script to install APKs from the command line quickly."""
 
-import optparse
+import argparse
+import glob
+import logging
 import os
 import sys
 
+from devil.android import apk_helper
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.utils import run_tests_helper
 from pylib import constants
-from pylib.device import device_errors
-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. '
+def main():
+  parser = argparse.ArgumentParser()
+
+  apk_group = parser.add_mutually_exclusive_group(required=True)
+  apk_group.add_argument('--apk', dest='apk_name',
+                         help='DEPRECATED The name of the apk containing the'
+                              ' application (with the .apk extension).')
+  apk_group.add_argument('apk_path', nargs='?',
+                         help='The path to the APK to install.')
+
+  # TODO(jbudorick): Remove once no clients pass --apk_package
+  parser.add_argument('--apk_package', help='DEPRECATED unused')
+  parser.add_argument('--split',
+                      action='append',
+                      dest='splits',
+                      help='A glob matching the apk splits. '
+                           'Can be specified multiple times.')
+  parser.add_argument('--keep_data',
+                      action='store_true',
+                      default=False,
+                      help='Keep the package data when installing '
+                           'the application.')
+  parser.add_argument('--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. '
+  parser.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.')
-  option_parser.add_option('-d', '--device', dest='device',
-                           help='Target device for apk to install on.')
+  parser.add_argument('-d', '--device', dest='device',
+                      help='Target device for apk to install on.')
+  parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
+  parser.add_argument('-v', '--verbose', action='count',
+                      help='Enable verbose logging.')
 
+  args = parser.parse_args()
 
-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.')
+  run_tests_helper.SetLogLevel(args.verbose)
+  constants.SetBuildType(args.build_type)
 
-  if not options.apk.endswith('.apk'):
-    options.apk += '.apk'
+  apk = args.apk_path or args.apk_name
+  if not apk.endswith('.apk'):
+    apk += '.apk'
+  if not os.path.exists(apk):
+    apk = os.path.join(constants.GetOutDirectory(), 'apks', apk)
+    if not os.path.exists(apk):
+      parser.error('%s not found.' % apk)
 
-  if not os.path.exists(options.apk):
-    options.apk = os.path.join(constants.GetOutDirectory(), 'apks',
-                               options.apk)
+  if args.splits:
+    splits = []
+    base_apk_package = apk_helper.ApkHelper(apk).GetPackageName()
+    for split_glob in args.splits:
+      apks = [f for f in glob.glob(split_glob) if f.endswith('.apk')]
+      if not apks:
+        logging.warning('No apks matched for %s.', split_glob)
+      for f in apks:
+        helper = apk_helper.ApkHelper(f)
+        if (helper.GetPackageName() == base_apk_package
+            and helper.GetSplitName()):
+          splits.append(f)
 
+  blacklist = (device_blacklist.Blacklist(args.blacklist_file)
+               if args.blacklist_file
+               else None)
+  devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
 
-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:
-    devices = [d for d in devices if d == options.device]
+  if args.device:
+    devices = [d for d in devices if d == args.device]
     if not devices:
-      raise device_errors.DeviceUnreachableError(options.device)
+      raise device_errors.DeviceUnreachableError(args.device)
   elif not devices:
     raise device_errors.NoDevicesError()
 
-  device_utils.DeviceUtils.parallel(devices).Install(
-      options.apk, reinstall=options.keep_data)
+  def blacklisting_install(device):
+    try:
+      if args.splits:
+        device.InstallSplitApk(apk, splits, reinstall=args.keep_data)
+      else:
+        device.Install(apk, reinstall=args.keep_data)
+    except device_errors.CommandFailedError:
+      logging.exception('Failed to install %s', args.apk_name)
+      if blacklist:
+        blacklist.Extend([str(device)], reason='install_failure')
+        logging.warning('Blacklisting %s', str(device))
+    except device_errors.CommandTimeoutError:
+      logging.exception('Timed out while installing %s', args.apk_name)
+      if blacklist:
+        blacklist.Extend([str(device)], reason='install_timeout')
+        logging.warning('Blacklisting %s', str(device))
+
+  device_utils.DeviceUtils.parallel(devices).pMap(blacklisting_install)
 
 
 if __name__ == '__main__':
-  sys.exit(main(sys.argv))
+  sys.exit(main())
 
diff --git a/build/android/adb_kill_chrome_shell b/build/android/adb_kill_blimp_client
similarity index 62%
rename from build/android/adb_kill_chrome_shell
rename to build/android/adb_kill_blimp_client
index 2b63c9a..6221e45 100755
--- a/build/android/adb_kill_chrome_shell
+++ b/build/android/adb_kill_blimp_client
@@ -1,17 +1,17 @@
 #!/bin/bash
 #
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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.
+# Kill a running instance of Blimp.
 #
 # Assumes you have sourced the build/android/envsetup.sh script.
 
-SHELL_PID_LINES=$(adb shell ps | grep ' org.chromium.chrome.shell')
+SHELL_PID_LINES=$(adb shell ps | grep -w 'org.chromium.blimp')
 VAL=$(echo "$SHELL_PID_LINES" | wc -l)
 if [ $VAL -lt 1 ] ; then
-   echo "Not running Chrome shell."
+   echo "Not running Blimp."
 else
    SHELL_PID=$(echo $SHELL_PID_LINES | awk '{print $2}')
    if [ "$SHELL_PID" != "" ] ; then
@@ -19,6 +19,6 @@
       adb shell kill $SHELL_PID
       set -
    else
-     echo "Chrome shell does not appear to be running."
+     echo "Blimp does not appear to be running."
    fi
 fi
diff --git a/build/android/adb_kill_chrome_shell b/build/android/adb_kill_chrome_public
similarity index 61%
copy from build/android/adb_kill_chrome_shell
copy to build/android/adb_kill_chrome_public
index 2b63c9a..5b539a0 100755
--- a/build/android/adb_kill_chrome_shell
+++ b/build/android/adb_kill_chrome_public
@@ -1,17 +1,17 @@
 #!/bin/bash
 #
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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.
+# Kill a running instance of ChromePublic.
 #
 # Assumes you have sourced the build/android/envsetup.sh script.
 
-SHELL_PID_LINES=$(adb shell ps | grep ' org.chromium.chrome.shell')
+SHELL_PID_LINES=$(adb shell ps | grep -w 'org.chromium.chrome')
 VAL=$(echo "$SHELL_PID_LINES" | wc -l)
 if [ $VAL -lt 1 ] ; then
-   echo "Not running Chrome shell."
+   echo "Not running ChromePublic."
 else
    SHELL_PID=$(echo $SHELL_PID_LINES | awk '{print $2}')
    if [ "$SHELL_PID" != "" ] ; then
@@ -19,6 +19,6 @@
       adb shell kill $SHELL_PID
       set -
    else
-     echo "Chrome shell does not appear to be running."
+     echo "ChromePublic does not appear to be running."
    fi
 fi
diff --git a/build/android/adb_reverse_forwarder.py b/build/android/adb_reverse_forwarder.py
index 3ce5359..64718f5 100755
--- a/build/android/adb_reverse_forwarder.py
+++ b/build/android/adb_reverse_forwarder.py
@@ -16,12 +16,12 @@
 import sys
 import time
 
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.utils import run_tests_helper
 from pylib import constants
 from pylib import forwarder
-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
 
 
 def main(argv):
@@ -36,6 +36,7 @@
                     help='Verbose level (multiple times for more)')
   parser.add_option('--device',
                     help='Serial number of device we should use.')
+  parser.add_option('--blacklist-file', help='Device blacklist JSON file.')
   parser.add_option('--debug', action='store_const', const='Debug',
                     dest='build_type', default='Release',
                     help='Use Debug build of host tools instead of Release.')
@@ -48,13 +49,16 @@
     sys.exit(1)
 
   try:
-    port_pairs = map(int, args[1:])
+    port_pairs = [int(a) for a in 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()
+  blacklist = (device_blacklist.Blacklist(options.blacklist_file)
+               if options.blacklist_file
+               else None)
+  devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
 
   if options.device:
     device = next((d for d in devices if d == options.device), None)
diff --git a/build/android/adb_run_chrome_shell b/build/android/adb_run_blimp_client
similarity index 63%
copy from build/android/adb_run_chrome_shell
copy to build/android/adb_run_blimp_client
index 79c4c32..4b3b4a8 100755
--- a/build/android/adb_run_chrome_shell
+++ b/build/android/adb_run_blimp_client
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
@@ -8,5 +8,5 @@
 
 adb shell am start \
   -a android.intent.action.VIEW \
-  -n org.chromium.chrome.shell/.ChromeShellActivity \
+  -n org.chromium.blimp/org.chromium.blimp.BlimpRendererActivity \
   ${optional_url:+-d "$optional_url"}
diff --git a/build/android/adb_run_chrome_shell b/build/android/adb_run_chrome_public
similarity index 64%
rename from build/android/adb_run_chrome_shell
rename to build/android/adb_run_chrome_public
index 79c4c32..bf15071 100755
--- a/build/android/adb_run_chrome_shell
+++ b/build/android/adb_run_chrome_public
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
@@ -8,5 +8,5 @@
 
 adb shell am start \
   -a android.intent.action.VIEW \
-  -n org.chromium.chrome.shell/.ChromeShellActivity \
+  -n org.chromium.chrome/com.google.android.apps.chrome.Main \
   ${optional_url:+-d "$optional_url"}
diff --git a/build/android/adb_run_system_webview_shell b/build/android/adb_run_system_webview_shell
new file mode 100755
index 0000000..5d0c0e4
--- /dev/null
+++ b/build/android/adb_run_system_webview_shell
@@ -0,0 +1,15 @@
+#!/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.
+
+# Runs a 'mini-browser' using System WebView with an optional url as parameter.
+# SystemWebViewShell.apk should be installed for this to work.
+
+optional_url=$1
+
+adb shell am start \
+  -a android.intent.action.VIEW \
+  -n org.chromium.webview_shell/.WebViewBrowserActivity \
+  ${optional_url:+-d "$optional_url"}
diff --git a/build/android/adb_system_webview_command_line b/build/android/adb_system_webview_command_line
new file mode 100755
index 0000000..376b0b3
--- /dev/null
+++ b/build/android/adb_system_webview_command_line
@@ -0,0 +1,17 @@
+#!/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_system_webview_command_line --enable-webgl
+#
+# To remove all content shell flags, pass an empty string for the flags:
+#   adb_android_webview_command_line ""
+
+exec $(dirname $0)/adb_command_line.py --device-path \
+    /data/local/tmp/webview-command-line "$@"
diff --git a/build/android/android.isolate b/build/android/android.isolate
new file mode 100644
index 0000000..ec94f80
--- /dev/null
+++ b/build/android/android.isolate
@@ -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.
+{
+  'variables': {
+    'files': [
+      '../../build/util/lib/common/',
+      '../../third_party/android_tools/sdk/build-tools/',
+      '../../third_party/android_tools/sdk/platform-tools/',
+      '../../third_party/appurify-python/',
+      '../../third_party/requests/',
+      '../../tools/swarming_client/',
+      '<(PRODUCT_DIR)/icudtl.dat',
+      '<(PRODUCT_DIR)/lib.java/chromium_commands.dex.jar',
+      '<(PRODUCT_DIR)/host_forwarder',
+      '<(PRODUCT_DIR)/forwarder_dist/',
+      '<(PRODUCT_DIR)/md5sum_bin_host',
+      '<(PRODUCT_DIR)/md5sum_dist/',
+      'devil/',
+      'gyp/util/',
+      'incremental_install/',
+      'lighttpd_server.py',
+      'pylib/',
+      'test_runner.py',
+    ]
+  }
+}
diff --git a/build/android/ant/apk-package.xml b/build/android/ant/apk-package.xml
index 99279a4..cb79560 100644
--- a/build/android/ant/apk-package.xml
+++ b/build/android/ant/apk-package.xml
@@ -54,6 +54,9 @@
   <property name="resource.package.file.name" value="${RESOURCE_PACKAGED_APK_NAME}" />
 
   <property name="intermediate.dex.file" location="${DEX_FILE_PATH}" />
+  <condition property="multidex.enabled" value="true">
+    <equals arg1="${MULTIDEX_ENABLED}" arg2="1"/>
+  </condition>
 
   <!-- Macro that enables passing a variable list of external jar files
        to ApkBuilder. -->
@@ -67,16 +70,35 @@
           debugpackaging="${build.is.packaging.debug}"
           debugsigning="${build.is.signing.debug}"
           verbose="${verbose}"
-          hascode="true"
+          hascode="${HAS_CODE}"
           previousBuildType="/"
           buildType="${build.is.packaging.debug}/${build.is.signing.debug}">
-        <dex path="${intermediate.dex.file}"/>
+        <dex path="${intermediate.dex.file}" />
         <nativefolder path="${native.libs.absolute.dir}" />
         <extra-jars/>
       </apkbuilder>
     </sequential>
   </macrodef>
 
+  <macrodef name="multidex-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="false"
+          previousBuildType="/"
+          buildType="${build.is.packaging.debug}/${build.is.signing.debug}">
+        <zip path="${intermediate.dex.file}" />
+        <nativefolder path="${native.libs.absolute.dir}" />
+        <extra-jars/>
+      </apkbuilder>
+    </sequential>
+  </macrodef>
 
   <!-- Packages the application. -->
   <target name="-package">
@@ -89,7 +111,14 @@
         </package-helper>
       </then>
       <else>
-        <package-helper />
+        <if condition="${multidex.enabled}">
+          <then>
+            <multidex-package-helper />
+          </then>
+          <else>
+            <package-helper />
+          </else>
+        </if>
       </else>
     </if>
   </target>
diff --git a/build/android/apkbuilder_action.gypi b/build/android/apkbuilder_action.gypi
new file mode 100644
index 0000000..e073e9b
--- /dev/null
+++ b/build/android/apkbuilder_action.gypi
@@ -0,0 +1,84 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is a helper to java_apk.gypi. It should be used to create an
+# action that runs ApkBuilder via ANT.
+#
+# Required variables:
+#  apk_name - File name (minus path & extension) of the output apk.
+#  apk_path - Path to output apk.
+#  package_input_paths - Late-evaluated list of resource zips.
+#  native_libs_dir - Path to lib/ directory to use. Set to an empty directory
+#    if no native libs are needed.
+# Optional variables:
+#  has_code - Whether to include classes.dex in the apk.
+#  dex_path - Path to classes.dex. Used only when has_code=1.
+#  extra_inputs - List of extra action inputs.
+{
+  'variables': {
+    'variables': {
+      'has_code%': 1,
+    },
+    'conditions': [
+      ['has_code == 0', {
+        'has_code_str': 'false',
+      }, {
+        'has_code_str': 'true',
+      }],
+    ],
+    'has_code%': '<(has_code)',
+    'extra_inputs%': [],
+    # 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).<(apk_name).gypcmd >@(package_input_paths))',
+    'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
+    'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
+  },
+  'action_name': 'apkbuilder_<(apk_name)',
+  'message': 'Packaging <(apk_name)',
+  'inputs': [
+    '<(DEPTH)/build/android/ant/apk-package.xml',
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/ant.py',
+    '<(resource_packaged_apk_path)',
+    '<@(extra_inputs)',
+    '>@(package_input_paths)',
+    '>(inputs_list_file)',
+  ],
+  'outputs': [
+    '<(apk_path)',
+  ],
+  'conditions': [
+    ['has_code == 1', {
+      'inputs': ['<(dex_path)'],
+      'action': [
+        '-DDEX_FILE_PATH=<(dex_path)',
+      ]
+    }],
+    ['enable_multidex == 1', {
+      'action': [
+        '-DMULTIDEX_ENABLED=1',
+      ]
+    }]
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/ant.py',
+    '--',
+    '-quiet',
+    '-DHAS_CODE=<(has_code_str)',
+    '-DANDROID_SDK_ROOT=<(android_sdk_root)',
+    '-DANDROID_SDK_TOOLS=<(android_sdk_tools)',
+    '-DRESOURCE_PACKAGED_APK_NAME=<(resource_packaged_apk_name)',
+    '-DNATIVE_LIBS_DIR=<(native_libs_dir)',
+    '-DAPK_NAME=<(apk_name)',
+    '-DCONFIGURATION_NAME=<(CONFIGURATION_NAME)',
+    '-DOUT_DIR=<(intermediate_dir)',
+    '-DUNSIGNED_APK_PATH=<(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/android/apksize.py b/build/android/apksize.py
new file mode 100755
index 0000000..ae5462b
--- /dev/null
+++ b/build/android/apksize.py
@@ -0,0 +1,228 @@
+#!/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 argparse
+import collections
+import json
+import logging
+import os
+import sys
+import zipfile
+
+_BASE_CHART = {
+    'format_version': '0.1',
+    'benchmark_name': 'apk_size',
+    'benchmark_description': 'APK size information.',
+    'trace_rerun_options': [],
+    'charts': {}
+}
+
+
+# TODO(rnephew): Add support for split apks.
+class ApkSizeInfo(object):
+
+  def __init__(self, path):
+    """ApkSizeInfo constructor.
+
+    Args:
+      path: Path to apk.
+    """
+    if not os.path.isfile(path):
+      raise IOError('Not a valid file path for apk.')
+    if not os.access(path, os.R_OK):
+      raise IOError('File is not readable.')
+    if not zipfile.is_zipfile(path):
+      raise TypeError('Not a valid apk')
+    logging.info('APK: %s', path)
+    self._apk_size = os.path.getsize(path)
+    self._zipfile = zipfile.ZipFile(path, 'r')
+    self._processed_files = None
+    self._compressed_size = 0
+    self._total_files = 0
+    self._uncompressed_size = 0
+    self._ProcessFiles()
+
+  def _ProcessFiles(self):
+    """Uses zipinfo to process apk file information."""
+    INITIAL_FILE_EXTENSION_INFO = {
+        'number': 0,
+        'compressed_bytes': 0,
+        'uncompressed_bytes': 0
+    }
+    self._processed_files = collections.defaultdict(
+        lambda: dict(INITIAL_FILE_EXTENSION_INFO))
+
+    for f in self._zipfile.infolist():
+      _, file_ext = os.path.splitext(f.filename)
+      file_ext = file_ext[1:] # Drop . from extension.
+
+      self._compressed_size += f.compress_size
+      self._total_files += 1
+      self._uncompressed_size += f.file_size
+      self._processed_files[file_ext]['number'] += 1
+      self._processed_files[file_ext]['compressed_bytes'] += f.compress_size
+      self._processed_files[file_ext]['uncompressed_bytes'] += f.file_size
+    return self._processed_files
+
+  def Compare(self, other_apk):
+    """Compares size information of two apks.
+
+    Args:
+      other_apk: ApkSizeInfo instance to compare size against.
+
+    Returns:
+      Dictionary of comparision results.
+    """
+    if not isinstance(other_apk, type(self)):
+      raise TypeError('Must pass it an ApkSizeInfo object')
+
+    other_lib_compressed = other_apk.processed_files['so']['compressed_bytes']
+    other_lib_uncompressed = (
+        other_apk.processed_files['so']['uncompressed_bytes'])
+    this_lib_compressed = self._processed_files['so']['compressed_bytes']
+    this_lib_uncompressed = self._processed_files['so']['uncompressed_bytes']
+
+    # TODO(rnephew) This will be made obsolete with modern and legacy apks being
+    # separate, a new method to compare will be required eventually.
+    return collections.OrderedDict([
+        ('APK_size_reduction',
+            other_apk.compressed_size - self.compressed_size),
+        ('ARM32_Legacy_install_or_upgrade_reduction',
+            (other_lib_compressed - this_lib_compressed) +
+            (other_lib_uncompressed - this_lib_uncompressed)),
+        ('ARM32_Legacy_system_image_reduction',
+            other_lib_compressed - this_lib_compressed),
+        ('ARM32_Modern_ARM64_install_or_upgrade_reduction',
+            other_lib_uncompressed - this_lib_uncompressed),
+        ('ARM32_Modern_ARM64_system_image_reduction',
+            other_lib_uncompressed - this_lib_uncompressed),
+    ])
+
+  @property
+  def apk_size(self):
+    return self._apk_size
+
+  @property
+  def compressed_size(self):
+    return self._compressed_size
+
+  @property
+  def total_files(self):
+    return self._total_files
+
+  @property
+  def uncompressed_size(self):
+    return self._uncompressed_size
+
+  @property
+  def processed_files(self):
+    return self._processed_files
+
+def add_value(chart_data, graph_title, trace_title, value, units,
+              improvement_direction='down', important=True):
+  chart_data['charts'].setdefault(graph_title, {})
+  chart_data['charts'][graph_title][trace_title] = {
+      'type': 'scalar',
+      'value': value,
+      'units': units,
+      'imporvement_direction': improvement_direction,
+      'important': important
+  }
+
+def chartjson_size_info(apk, output_dir):
+  """Sends size information to perf dashboard.
+
+  Args:
+    apk: ApkSizeInfo object
+  """
+  data = _BASE_CHART.copy()
+  files = apk.processed_files
+  add_value(data, 'files', 'total', apk.total_files, 'count')
+  add_value(data, 'size', 'total_size_compressed', apk.compressed_size, 'bytes')
+  add_value(data, 'size', 'total_size_uncompressed', apk.uncompressed_size,
+            'bytes')
+  add_value(data, 'size', 'apk_overhead', apk.apk_size - apk.compressed_size,
+           'bytes')
+  for ext in files:
+    add_value(data, 'files', ext, files[ext]['number'], 'count')
+    add_value(data, 'size_compressed', ext, files[ext]['compressed_bytes'],
+              'bytes')
+    add_value(data, 'size_uncompressed', ext, files[ext]['uncompressed_bytes'],
+              'bytes')
+
+  logging.info('Outputing data to json file %s', output_dir)
+  with open(os.path.join(output_dir, 'results-chart.json'), 'w') as json_file:
+    json.dump(data, json_file)
+
+def print_human_readable_size_info(apk):
+  """Prints size information in human readable format.
+
+  Args:
+    apk: ApkSizeInfo object
+  """
+  files = apk.processed_files
+  logging.critical('Stats for files as they exist within the apk:')
+  for ext in files:
+    logging.critical('  %-8s %s bytes in %s files', ext,
+                     files[ext]['compressed_bytes'], files[ext]['number'])
+  logging.critical('--------------------------------------')
+  logging.critical(
+      'All Files: %s bytes in %s files', apk.compressed_size, apk.total_files)
+  logging.critical('APK Size: %s', apk.apk_size)
+  logging.critical('APK overhead: %s', apk.apk_size - apk.compressed_size)
+  logging.critical('--------------------------------------')
+  logging.critical('Stats for files when extracted from the apk:')
+  for ext in files:
+    logging.critical('  %-8s %s bytes in %s files', ext,
+                     files[ext]['uncompressed_bytes'], files[ext]['number'])
+  logging.critical('--------------------------------------')
+  logging.critical(
+      'All Files: %s bytes in %s files', apk.uncompressed_size, apk.total_files)
+
+def chartjson_compare(compare_dict, output_dir):
+  """Sends size comparison between two apks to perf dashboard.
+
+  Args:
+    compare_dict: Dictionary returned from APkSizeInfo.Compare()
+  """
+  data = _BASE_CHART.copy()
+  for key, value in compare_dict.iteritems():
+    add_value(data, 'compare', key, value, 'bytes')
+
+  logging.info('Outputing data to json file %s', output_dir)
+  with open(os.path.join(output_dir, 'results-chart.json'), 'w') as json_file:
+    json.dump(data, json_file)
+
+def print_human_readable_compare(compare_dict):
+  """Prints size comparison between two apks in human readable format.
+
+  Args:
+    compare_dict: Dictionary returned from ApkSizeInfo.Compare()
+  """
+  for key, value in compare_dict.iteritems():
+    logging.critical('  %-50s %s bytes', key, value)
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('file_path')
+  parser.add_argument('-c', '--compare', help='APK to compare against.')
+  parser.add_argument('-o', '--output-dir',
+                      help='Sets it to return data in bot readable format')
+  parser.add_argument('-d', '--device', help='Dummy option for perf runner.')
+  args = parser.parse_args()
+
+  apk = ApkSizeInfo(args.file_path)
+  if args.compare:
+    compare_dict = apk.Compare(ApkSizeInfo(args.compare))
+    print_human_readable_compare(compare_dict)
+    if args.output_dir:
+      chartjson_compare(compare_dict, args.output_dir)
+  else:
+    print_human_readable_size_info(apk)
+    if args.output_dir:
+       chartjson_size_info(apk, args.output_dir)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/asan_symbolize.py b/build/android/asan_symbolize.py
index 10087a6..0aa1ab8 100755
--- a/build/android/asan_symbolize.py
+++ b/build/android/asan_symbolize.py
@@ -50,6 +50,7 @@
   for asan_lib in asan_libs:
     if os.path.basename(library) == os.path.basename(asan_lib):
       return '/' + asan_lib
+  # pylint: disable=no-member
   return symbol.TranslateLibPath(library)
 
 
@@ -67,6 +68,7 @@
   for library, items in libraries.iteritems():
     libname = _TranslateLibPath(library, asan_libs)
     lib_relative_addrs = set([i['rel_address'] for i in items])
+    # pylint: disable=no-member
     info_dict = symbol.SymbolInformationForSet(libname,
                                                lib_relative_addrs,
                                                True)
diff --git a/build/android/avd.py b/build/android/avd.py
index c45544f..4b7d191 100755
--- a/build/android/avd.py
+++ b/build/android/avd.py
@@ -16,15 +16,14 @@
 import re
 import sys
 
-from pylib import cmd_helper
+from devil.utils 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')
+  emulator_sdk = constants.ANDROID_SDK_ROOT
   os.environ['ANDROID_SDK_ROOT'] = emulator_sdk
 
   opt_parser = optparse.OptionParser(description='AVD script.')
@@ -38,13 +37,29 @@
   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)
+  opt_parser.add_option('--kill-existing-emulators', action='store_true',
+                        dest='kill', default=False,
+                        help='Shutdown all existing emulators')
 
   options, _ = opt_parser.parse_args(argv[1:])
 
-  logging.basicConfig(level=logging.INFO,
-                      format='# %(asctime)-15s: %(message)s')
   logging.root.setLevel(logging.INFO)
 
+  # Make sure --kill-existing-emulators is mutually exclusive with other options
+  if options.kill and len(argv[1:]) > 1:
+    logging.error('--kill-existing-emulators was specified. '
+                  'Ignoring all other arguments.')
+
+  if options.kill:
+    logging.info('Killing all existing emulator and existing the program')
+    emulator.KillAllEmulators()
+    return
+
+ # Check if SDK exist in ANDROID_SDK_ROOT
+  if not install_emulator_deps.CheckSDK():
+    raise Exception('Emulator SDK not installed in %s'
+                     % constants.ANDROID_SDK_ROOT)
+
   # 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?
@@ -58,16 +73,11 @@
                        '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 = os.path.join(constants.ANDROID_SDK_ROOT, 'tools',
                            'android')
     avds_output = cmd_helper.GetCmdOutput([android, 'list', 'avd'])
     names = re.findall(r'Name: (\w+)', avds_output)
@@ -75,7 +85,7 @@
     try:
       avd_index = names.index(options.name)
     except ValueError:
-      logging.critical('ERROR: Specified AVD %s does not exist.' % options.name)
+      logging.critical('ERROR: Specified AVD %s does not exist.', options.name)
       return 1
     api_level = int(api_levels[avd_index])
 
diff --git a/build/android/bb_run_sharded_steps.py b/build/android/bb_run_sharded_steps.py
index 6aeba5b..1775dc1 100755
--- a/build/android/bb_run_sharded_steps.py
+++ b/build/android/bb_run_sharded_steps.py
@@ -12,7 +12,7 @@
 import optparse
 import sys
 
-from pylib import cmd_helper
+from devil.utils import cmd_helper
 
 
 def main(argv):
diff --git a/build/android/buildbot/OWNERS b/build/android/buildbot/OWNERS
deleted file mode 100644
index f289720..0000000
--- a/build/android/buildbot/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-set noparent
-
-cmp@chromium.org
-jbudorick@chromium.org
-navabi@chromium.org
-
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
index 8690a60..6dd5ca5 100755
--- a/build/android/buildbot/bb_device_status_check.py
+++ b/build/android/buildbot/bb_device_status_check.py
@@ -5,241 +5,29 @@
 # found in the LICENSE file.
 
 """A class to keep track of devices across builds and report state."""
+
+import argparse
 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
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+from devil.android import battery_utils
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_list
+from devil.android import device_utils
+from devil.android.sdk import adb_wrapper
+from devil.utils import lsusb
+from devil.utils import reset_usb
+from devil.utils import run_tests_helper
 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
+_RE_DEVICE_ID = re.compile(r'Device ID = (\d+)')
 
 
 def KillAllAdb():
@@ -267,145 +55,339 @@
       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.')
+def _IsBlacklisted(serial, blacklist):
+  return blacklist and serial in blacklist.Read()
 
-  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()
-
+def _BatteryStatus(device, blacklist):
+  battery_info = {}
   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)
+    battery = battery_utils.BatteryUtils(device)
+    battery_info = battery.GetBatteryInfo(timeout=5)
+    battery_level = int(battery_info.get('level', 100))
+
+    if battery_level < 15:
+      logging.error('Critically low battery level (%d)', battery_level)
+      battery = battery_utils.BatteryUtils(device)
+      if not battery.GetCharging():
+        battery.SetCharging(True)
+      if blacklist:
+        blacklist.Extend([device.adb.GetDeviceSerial()], reason='low_battery')
+
+  except device_errors.CommandFailedError:
+    logging.exception('Failed to get battery information for %s',
+                      str(device))
+
+  return battery_info
+
+
+def _IMEISlice(device):
+  imei_slice = ''
+  try:
+    for l in device.RunShellCommand(['dumpsys', 'iphonesubinfo'],
+                                    check_return=True, timeout=5):
+      m = _RE_DEVICE_ID.match(l)
+      if m:
+        imei_slice = m.group(1)[-6:]
+  except device_errors.CommandFailedError:
+    logging.exception('Failed to get IMEI slice for %s', str(device))
+
+  return imei_slice
+
+
+def DeviceStatus(devices, blacklist):
+  """Generates status information for the given devices.
+
+  Args:
+    devices: The devices to generate status for.
+    blacklist: The current device blacklist.
+  Returns:
+    A dict of the following form:
+    {
+      '<serial>': {
+        'serial': '<serial>',
+        'adb_status': str,
+        'usb_status': bool,
+        'blacklisted': bool,
+        # only if the device is connected and not blacklisted
+        'type': ro.build.product,
+        'build': ro.build.id,
+        'build_detail': ro.build.fingerprint,
+        'battery': {
+          ...
+        },
+        'imei_slice': str,
+        'wifi_ip': str,
+      },
+      ...
+    }
+  """
+  adb_devices = {
+    a[0].GetDeviceSerial(): a
+    for a in adb_wrapper.AdbWrapper.Devices(desired_state=None, long_list=True)
+  }
+  usb_devices = set(lsusb.get_android_devices())
+
+  def blacklisting_device_status(device):
+    serial = device.adb.GetDeviceSerial()
+    adb_status = (
+        adb_devices[serial][1] if serial in adb_devices
+        else 'unknown')
+    usb_status = bool(serial in usb_devices)
+
+    device_status = {
+      'serial': serial,
+      'adb_status': adb_status,
+      'usb_status': usb_status,
+    }
+
+    if adb_status == 'device':
+      if not _IsBlacklisted(serial, blacklist):
+        try:
+          build_product = device.build_product
+          build_id = device.build_id
+          build_fingerprint = device.GetProp('ro.build.fingerprint', cache=True)
+          wifi_ip = device.GetProp('dhcp.wlan0.ipaddress')
+          battery_info = _BatteryStatus(device, blacklist)
+          imei_slice = _IMEISlice(device)
+
+          if (device.product_name == 'mantaray' and
+              battery_info.get('AC powered', None) != 'true'):
+            logging.error('Mantaray device not connected to AC power.')
+
+          device_status.update({
+            'ro.build.product': build_product,
+            'ro.build.id': build_id,
+            'ro.build.fingerprint': build_fingerprint,
+            'battery': battery_info,
+            'imei_slice': imei_slice,
+            'wifi_ip': wifi_ip,
+
+            # TODO(jbudorick): Remove these once no clients depend on them.
+            'type': build_product,
+            'build': build_id,
+            'build_detail': build_fingerprint,
+          })
+
+        except device_errors.CommandFailedError:
+          logging.exception('Failure while getting device status for %s.',
+                            str(device))
+          if blacklist:
+            blacklist.Extend([serial], reason='status_check_failure')
+
+        except device_errors.CommandTimeoutError:
+          logging.exception('Timeout while getting device status for %s.',
+                            str(device))
+          if blacklist:
+            blacklist.Extend([serial], reason='status_check_timeout')
+
+    elif blacklist:
+      blacklist.Extend([serial], reason=adb_status)
+
+    device_status['blacklisted'] = _IsBlacklisted(serial, blacklist)
+
+    return device_status
+
+  parallel_devices = device_utils.DeviceUtils.parallel(devices)
+  statuses = parallel_devices.pMap(blacklisting_device_status).pGet(None)
+  return statuses
+
+
+def RecoverDevices(devices, blacklist):
+  """Attempts to recover any inoperable devices in the provided list.
+
+  Args:
+    devices: The list of devices to attempt to recover.
+    blacklist: The current device blacklist, which will be used then
+      reset.
+  Returns:
+    Nothing.
+  """
+
+  statuses = DeviceStatus(devices, blacklist)
+
+  should_restart_usb = set(
+      status['serial'] for status in statuses
+      if (not status['usb_status']
+          or status['adb_status'] == 'unknown'))
+  should_restart_adb = should_restart_usb.union(set(
+      status['serial'] for status in statuses
+      if status['adb_status'] in ('offline', 'unauthorized')))
+  should_reboot_device = should_restart_adb.union(set(
+      status['serial'] for status in statuses
+      if status['blacklisted']))
+
+  logging.debug('Should restart USB for:')
+  for d in should_restart_usb:
+    logging.debug('  %s', d)
+  logging.debug('Should restart ADB for:')
+  for d in should_restart_adb:
+    logging.debug('  %s', d)
+  logging.debug('Should reboot:')
+  for d in should_reboot_device:
+    logging.debug('  %s', d)
+
+  if blacklist:
+    blacklist.Reset()
+
+  if should_restart_adb:
     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
+  for serial in should_restart_usb:
+    try:
+      reset_usb.reset_android_usb(serial)
+    except (IOError, device_errors.DeviceUnreachableError):
+      logging.exception('Unable to reset USB for %s.', serial)
+      if blacklist:
+        blacklist.Extend([serial], reason='usb_failure')
 
-  # TODO(navabi): Test to make sure this fails and then fix call
-  offline_devices = android_commands.GetAttachedDevices(
-      hardware=False, emulator=False, offline=True)
+  def blacklisting_recovery(device):
+    if _IsBlacklisted(device.adb.GetDeviceSerial(), blacklist):
+      logging.debug('%s is blacklisted, skipping recovery.', str(device))
+      return
 
-  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]))
+    if str(device) in should_reboot_device:
+      try:
+        device.WaitUntilFullyBooted(retries=0)
+        return
+      except (device_errors.CommandTimeoutError,
+              device_errors.CommandFailedError):
+        logging.exception('Failure while waiting for %s. '
+                          'Attempting to recover.', str(device))
+
+      try:
+        try:
+          device.Reboot(block=False, timeout=5, retries=0)
+        except device_errors.CommandTimeoutError:
+          logging.warning('Timed out while attempting to reboot %s normally.'
+                          'Attempting alternative reboot.', str(device))
+          # The device drops offline before we can grab the exit code, so
+          # we don't check for status.
+          device.adb.Root()
+          device.adb.Shell('echo b > /proc/sysrq-trigger', expect_status=None,
+                           timeout=5, retries=0)
+      except device_errors.CommandFailedError:
+        logging.exception('Failed to reboot %s.', str(device))
+        if blacklist:
+          blacklist.Extend([device.adb.GetDeviceSerial()],
+                           reason='reboot_failure')
+      except device_errors.CommandTimeoutError:
+        logging.exception('Timed out while rebooting %s.', str(device))
+        if blacklist:
+          blacklist.Extend([device.adb.GetDeviceSerial()],
+                           reason='reboot_timeout')
+
+      try:
+        device.WaitUntilFullyBooted(retries=0)
+      except device_errors.CommandFailedError:
+        logging.exception('Failure while waiting for %s.', str(device))
+        if blacklist:
+          blacklist.Extend([device.adb.GetDeviceSerial()],
+                           reason='reboot_failure')
+      except device_errors.CommandTimeoutError:
+        logging.exception('Timed out while waiting for %s.', str(device))
+        if blacklist:
+          blacklist.Extend([device.adb.GetDeviceSerial()],
+                           reason='reboot_timeout')
+
+  device_utils.DeviceUtils.parallel(devices).pMap(blacklisting_recovery)
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--out-dir',
+                      help='Directory where the device path is stored',
+                      default=os.path.join(constants.DIR_SOURCE_ROOT, 'out'))
+  parser.add_argument('--restart-usb', action='store_true',
+                      help='DEPRECATED. '
+                           'This script now always tries to reset USB.')
+  parser.add_argument('--json-output',
+                      help='Output JSON information into a specified file.')
+  parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
+  parser.add_argument('-v', '--verbose', action='count', default=1,
+                      help='Log more information.')
+
+  args = parser.parse_args()
+
+  run_tests_helper.SetLogLevel(args.verbose)
+
+  blacklist = (device_blacklist.Blacklist(args.blacklist_file)
+               if args.blacklist_file
+               else None)
+
+  last_devices_path = os.path.join(
+      args.out_dir, device_list.LAST_DEVICES_FILENAME)
+  try:
+    expected_devices = set(
+        device_list.GetPersistentDeviceList(last_devices_path))
+  except IOError:
+    expected_devices = set()
+
+  usb_devices = set(lsusb.get_android_devices())
+  devices = [device_utils.DeviceUtils(s)
+             for s in expected_devices.union(usb_devices)]
+
+  RecoverDevices(devices, blacklist)
+  statuses = DeviceStatus(devices, blacklist)
+
+  # Log the state of all devices.
+  for status in statuses:
+    logging.info(status['serial'])
+    adb_status = status.get('adb_status')
+    blacklisted = status.get('blacklisted')
+    logging.info('  USB status: %s',
+                 'online' if status.get('usb_status') else 'offline')
+    logging.info('  ADB status: %s', adb_status)
+    logging.info('  Blacklisted: %s', str(blacklisted))
+    if adb_status == 'device' and not blacklisted:
+      logging.info('  Device type: %s', status.get('ro.build.product'))
+      logging.info('  OS build: %s', status.get('ro.build.id'))
+      logging.info('  OS build fingerprint: %s',
+                   status.get('ro.build.fingerprint'))
+      logging.info('  Battery state:')
+      for k, v in status.get('battery', {}).iteritems():
+        logging.info('    %s: %s', k, v)
+      logging.info('  IMEI slice: %s', status.get('imei_slice'))
+      logging.info('  WiFi IP: %s', status.get('wifi_ip'))
+
+  # Update the last devices file.
+  device_list.WritePersistentDeviceList(
+      last_devices_path,
+      [status['serial'] for status in statuses])
 
   # 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:
+      for status in statuses:
         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:
+          if status['adb_status'] == 'device':
+            f.write('{serial} {adb_status} {build_product} {build_id} '
+                    '{temperature:.1f}C {level}%\n'.format(
+                serial=status['serial'],
+                adb_status=status['adb_status'],
+                build_product=status['type'],
+                build_id=status['build'],
+                temperature=float(status['battery']['temperature']) / 10,
+                level=status['battery']['level']
+            ))
+          else:
+            f.write('{serial} {adb_status}'.format(
+                serial=status['serial'],
+                adb_status=status['adb_status']
+            ))
+        except Exception: # pylint: disable=broad-except
           pass
 
-  err_msg = CheckForMissingDevices(options, devices) or []
+  # Dump the device statuses to JSON.
+  if args.json_output:
+    with open(args.json_output, 'wb') as f:
+      f.write(json.dumps(statuses, indent=4))
 
-  unique_types = list(set(types))
-  unique_builds = list(set(builds))
+  live_devices = [status['serial'] for status in statuses
+                  if (status['adb_status'] == 'device'
+                      and not _IsBlacklisted(status['serial'], blacklist))]
 
-  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 all devices failed, or if there are no devices, it's an infra error.
+  return 0 if live_devices else constants.INFRA_EXIT_CODE
 
 
 if __name__ == '__main__':
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py
index 665c736..e4d2998 100755
--- a/build/android/buildbot/bb_device_steps.py
+++ b/build/android/buildbot/bb_device_steps.py
@@ -18,8 +18,8 @@
 
 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
 import provision_devices
+from devil.android import device_utils
 from pylib import constants
-from pylib.device import device_utils
 from pylib.gtest import gtest_config
 
 CHROME_SRC_DIR = bb_utils.CHROME_SRC
@@ -63,13 +63,12 @@
       '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',
+    I('ChromePublic',
+      'ChromePublic.apk',
+      'org.chromium.chrome',
+      'ChromePublicTest',
       '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),
+      isolate_file_path='chrome/chrome_public_test_apk.isolate'),
     I('AndroidWebView',
       'AndroidWebView.apk',
       'org.chromium.android_webview.shell',
@@ -96,14 +95,11 @@
 VALID_TESTS = set([
     'base_junit_tests',
     'chromedriver',
-    'chrome_proxy',
     'components_browsertests',
     'gfx_unittests',
     'gl_unittests',
     'gpu',
     'python_unittests',
-    'telemetry_unittests',
-    'telemetry_perf_unittests',
     'ui',
     'unit',
     'webkit',
@@ -172,7 +168,7 @@
   if not suites_options:
     suites_options = {}
 
-  args = ['--verbose']
+  args = ['--verbose', '--blacklist-file', 'out/bad_devices.json']
   if options.target == 'Release':
     args.append('--release')
   if options.asan:
@@ -199,46 +195,13 @@
   bb_annotations.PrintNamedStep('chromedriver_annotation')
   RunCmd(['chrome/test/chromedriver/run_buildbot_steps.py',
           '--android-packages=%s,%s,%s,%s' %
-          ('chrome_shell',
+          ('chromium',
            '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 = device_utils.DeviceUtils.HealthyDevices()
-  if devices:
-    args = args + ['--device', devices[0].adb.GetDeviceSerial()]
-  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 = device_utils.DeviceUtils.HealthyDevices()
-  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.
@@ -251,7 +214,10 @@
   if print_step:
     bb_annotations.PrintNamedStep('install_%s' % test.name.lower())
 
-  args = ['--apk_package', test.apk_package]
+  args = [
+      '--apk_package', test.apk_package,
+      '--blacklist-file', 'out/bad_devices.json',
+  ]
   if options.target == 'Release':
     args.append('--release')
   args.append(test.apk)
@@ -274,7 +240,10 @@
 
   if test.apk:
     InstallApk(options, test)
-  args = ['--test-apk', test.test_apk, '--verbose']
+  args = [
+      '--test-apk', test.test_apk, '--verbose',
+      '--blacklist-file', 'out/bad_devices.json'
+  ]
   if test.test_data:
     args.extend(['--test_data', test.test_data])
   if options.target == 'Release':
@@ -478,7 +447,10 @@
     # 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]
+  provision_cmd = [
+      'build/android/provision_devices.py', '-t', options.target,
+      '--blacklist-file', 'out/bad_devices.json'
+  ]
   if options.auto_reconnect:
     provision_cmd.append('--auto-reconnect')
   if options.skip_wipe:
@@ -490,7 +462,10 @@
 
 def DeviceStatusCheck(options):
   bb_annotations.PrintNamedStep('device_status_check')
-  cmd = ['build/android/buildbot/bb_device_status_check.py']
+  cmd = [
+      'build/android/buildbot/bb_device_status_check.py',
+      '--blacklist-file', 'out/bad_devices.json',
+  ]
   if options.restart_usb:
     cmd.append('--restart-usb')
   RunCmd(cmd, halt_on_failure=True)
@@ -511,14 +486,6 @@
   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)
@@ -535,7 +502,7 @@
 
   bb_annotations.PrintNamedStep('pixel_tests')
   RunCmd(['content/test/gpu/run_gpu_test.py',
-          'pixel',
+          'pixel', '-v',
           '--browser',
           'android-content-shell',
           '--build-revision',
@@ -546,27 +513,35 @@
           '--os-type',
           'android',
           '--test-machine-name',
-          EscapeBuilderName(builder_name)])
+          EscapeBuilderName(builder_name),
+          '--android-blacklist-file',
+          'out/bad_devices.json'])
 
   bb_annotations.PrintNamedStep('webgl_conformance_tests')
-  RunCmd(['content/test/gpu/run_gpu_test.py',
+  RunCmd(['content/test/gpu/run_gpu_test.py', '-v',
           '--browser=android-content-shell', 'webgl_conformance',
-          '--webgl-conformance-version=1.0.1'])
+          '--webgl-conformance-version=1.0.1',
+          '--android-blacklist-file',
+          'out/bad_devices.json'])
 
   bb_annotations.PrintNamedStep('android_webview_webgl_conformance_tests')
-  RunCmd(['content/test/gpu/run_gpu_test.py',
+  RunCmd(['content/test/gpu/run_gpu_test.py', '-v',
           '--browser=android-webview-shell', 'webgl_conformance',
-          '--webgl-conformance-version=1.0.1'])
+          '--webgl-conformance-version=1.0.1',
+          '--android-blacklist-file',
+          'out/bad_devices.json'])
 
   bb_annotations.PrintNamedStep('gpu_rasterization_tests')
   RunCmd(['content/test/gpu/run_gpu_test.py',
-          'gpu_rasterization',
+          'gpu_rasterization', '-v',
           '--browser',
           'android-content-shell',
           '--build-revision',
           str(revision),
           '--test-machine-name',
-          EscapeBuilderName(builder_name)])
+          EscapeBuilderName(builder_name),
+          '--android-blacklist-file',
+          'out/bad_devices.json'])
 
 
 def RunPythonUnitTests(_options):
@@ -580,7 +555,6 @@
       ('base_junit_tests',
           lambda _options: RunJunitSuite('base_junit_tests')),
       ('chromedriver', RunChromeDriverTests),
-      ('chrome_proxy', RunChromeProxyTests),
       ('components_browsertests',
           lambda options: RunTestSuites(options, ['components_browsertests'])),
       ('gfx_unittests',
@@ -589,8 +563,6 @@
           lambda options: RunTestSuites(options, ['gl_unittests'])),
       ('gpu', RunGPUTests),
       ('python_unittests', RunPythonUnitTests),
-      ('telemetry_unittests', RunTelemetryUnitTests),
-      ('telemetry_perf_unittests', RunTelemetryPerfUnitTests),
       ('ui', RunInstrumentationTests),
       ('unit', RunUnitTests),
       ('webkit', RunWebkitTests),
@@ -779,6 +751,7 @@
 
   setattr(options, 'target', options.factory_properties.get('target', 'Debug'))
 
+  # pylint: disable=global-statement
   if options.chrome_output_dir:
     global CHROME_OUT_DIR
     global LOGCAT_DIR
diff --git a/build/android/buildbot/bb_run_bot.py b/build/android/buildbot/bb_run_bot.py
index 0c8a977..5f57c9b 100755
--- a/build/android/buildbot/bb_run_bot.py
+++ b/build/android/buildbot/bb_run_bot.py
@@ -115,15 +115,11 @@
 
 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']
   trial_tests = [
       'base_junit_tests',
       'components_browsertests',
@@ -152,8 +148,7 @@
         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])),
+        T(std_tests, ['--cleanup', flakiness_server])),
       B('main-tests', H(std_test_steps),
         T(std_tests, ['--cleanup', flakiness_server])),
 
@@ -164,7 +159,7 @@
       B('blink-try-builder', H(compile_step)),
       B('chromedriver-fyi-tests-dbg', H(std_test_steps),
         T(['chromedriver'],
-          ['--install=ChromeShell', '--install=ChromeDriverWebViewShell',
+          ['--install=ChromePublic', '--install=ChromeDriverWebViewShell',
            '--skip-wipe', '--disable-location', '--cleanup'])),
       B('fyi-x86-builder-dbg',
         H(compile_step + std_host_tests, experimental, target_arch='ia32')),
@@ -180,7 +175,7 @@
                       '--coverage-bucket', CHROMIUM_COVERAGE_BUCKET,
                       '--cleanup'])),
       B('user-build-fyi-tests-dbg', H(std_test_steps),
-        T(sorted(telemetry_tests_user_build + trial_tests))),
+        T(sorted(trial_tests))),
       B('fyi-component-builder-tests-dbg',
         H(compile_step, extra_gyp='component=shared_library'),
         T(std_tests, ['--experimental', flakiness_server])),
@@ -192,7 +187,7 @@
         H(['bisect_perf_regression']),
         T([], ['--chrome-output-dir', bisect_chrome_output_dir])),
       B('perf-tests-rel', H(std_test_steps),
-        T([], ['--install=ChromeShell', '--cleanup'])),
+        T([], ['--cleanup'])),
       B('webkit-latest-webkit-tests', H(std_test_steps),
         T(['webkit_layout', 'webkit'], ['--cleanup', '--auto-reconnect'])),
       B('webkit-latest-contentshell', H(compile_step),
diff --git a/build/android/buildbot/bb_utils.py b/build/android/buildbot/bb_utils.py
index 3c16cc2..b78fec0 100644
--- a/build/android/buildbot/bb_utils.py
+++ b/build/android/buildbot/bb_utils.py
@@ -5,13 +5,13 @@
 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 devil.utils import cmd_helper
 from pylib import constants
 
 
@@ -33,7 +33,7 @@
 
 def CommandToString(command):
   """Returns quoted command that can be run in bash shell."""
-  return ' '.join(map(pipes.quote, command))
+  return ' '.join(cmd_helper.SingleQuote(c) for c in command)
 
 
 def SpawnCmd(command, stdout=None, cwd=CHROME_SRC):
diff --git a/build/android/chrome_with_libs.gyp b/build/android/chrome_with_libs.gyp
deleted file mode 100644
index 690be88..0000000
--- a/build/android/chrome_with_libs.gyp
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright 2013 The Chromium Authors. All 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/copy_ex.gypi b/build/android/copy_ex.gypi
new file mode 100644
index 0000000..8c49d24
--- /dev/null
+++ b/build/android/copy_ex.gypi
@@ -0,0 +1,79 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Copy files to a directory with the option to clear directory first.
+#
+# Variables:
+#   dest_path - directory to copy files to.
+#   src_files - optional, a list of files to copy without changing name.
+#   clear - optional, if set, clear directory before copying files.
+#   renaming_sources - optional, a list of files to copy and rename.
+#   renaming_destinations - optional, a list of new file names corresponding to
+#                           renaming_sources.
+#
+# Exmaple
+#  {
+#    'target_name': 'copy_assets',
+#    'type': 'none',
+#    'variables': {
+#      'dest_path': 'apk/assets/path',
+#      'src_files': ['path1/fr.pak'],
+#      'clear': 1,
+#      # path2/old1 and path3/old2 will be copied to apk/assets/path and
+#      # renamed to new1, new2 respectly.
+#      'renaming_sources': ['path2/old1', 'path3/old2'],
+#      'renaming_destinations': ['new1', 'new2'],
+#    },
+#    'includes': [ '../build/android/copy_ex.gypi' ],
+#  },
+#
+{
+  'variables': {
+    'clear%': 0,
+    'src_files%': [],
+    'renaming_sources%': [],
+    'renaming_destinations%': [],
+  },
+  'actions': [{
+    'action_name': '<(_target_name)_copy_ex',
+    'variables': {
+      'additional_args':[],
+      'local_inputs': [],
+      'dest_files': [],
+      'conditions': [
+        ['clear == 1', {
+          'additional_args': ['--clear'],
+        }],
+        ['src_files != []', {
+          'additional_args': ['--files', '<(src_files)'],
+          'local_inputs': ['<@(src_files)'],
+          # src_files will be used to generate destination files path for
+          # outputs.
+          'dest_files': ['<@(src_files)'],
+        }],
+        ['renaming_sources != []', {
+          'additional_args': [
+            '--renaming-sources', '<(renaming_sources)',
+            '--renaming-destinations', '<(renaming_destinations)'
+          ],
+          'local_inputs': ['<@(renaming_sources)'],
+          'dest_files': ['<@(renaming_destinations)'],
+        }],
+      ],
+    },
+    'inputs': [
+      '<(DEPTH)/build/android/gyp/copy_ex.py',
+      '<(DEPTH)/build/android/gyp/generate_copy_ex_outputs.py',
+      '<@(local_inputs)',
+    ],
+    'outputs': [
+      '<!@pymod_do_main(generate_copy_ex_outputs --dest-path <(dest_path) --src-files <(dest_files))',
+    ],
+    'action': [
+      'python', '<(DEPTH)/build/android/gyp/copy_ex.py',
+      '--dest', '<(dest_path)',
+      '<@(additional_args)',
+    ],
+  }],
+}
diff --git a/build/android/cpufeatures.gypi b/build/android/cpufeatures.gypi
deleted file mode 100644
index 672ff1f..0000000
--- a/build/android/cpufeatures.gypi
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright (c) 2012 The Chromium 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/devil/OWNERS b/build/android/devil/OWNERS
new file mode 100644
index 0000000..fd584fc
--- /dev/null
+++ b/build/android/devil/OWNERS
@@ -0,0 +1,4 @@
+jbudorick@chromium.org
+mikecase@chromium.org
+perezju@chromium.org
+rnephew@chromium.org
diff --git a/build/android/pylib/uiautomator/__init__.py b/build/android/devil/__init__.py
similarity index 61%
copy from build/android/pylib/uiautomator/__init__.py
copy to build/android/devil/__init__.py
index cda7672..50b23df 100644
--- a/build/android/pylib/uiautomator/__init__.py
+++ b/build/android/devil/__init__.py
@@ -1,4 +1,3 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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/__init__.py b/build/android/devil/android/__init__.py
similarity index 61%
copy from build/android/pylib/uiautomator/__init__.py
copy to build/android/devil/android/__init__.py
index cda7672..50b23df 100644
--- a/build/android/pylib/uiautomator/__init__.py
+++ b/build/android/devil/android/__init__.py
@@ -1,4 +1,3 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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/devil/android/apk_helper.py b/build/android/devil/android/apk_helper.py
new file mode 100644
index 0000000..81c49cf
--- /dev/null
+++ b/build/android/devil/android/apk_helper.py
@@ -0,0 +1,141 @@
+# Copyright (c) 2013 The Chromium 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 re
+
+from devil.android.sdk import aapt
+
+
+_MANIFEST_ATTRIBUTE_RE = re.compile(
+    r'\s*A: ([^\(\)= ]*)(?:\([^\(\)= ]*\))?='
+    r'(?:"(.*)" \(Raw: .*\)|\(type.*?\)(.*))$')
+_MANIFEST_ELEMENT_RE = re.compile(r'\s*(?:E|N): (\S*) .*$')
+
+
+def GetPackageName(apk_path):
+  """Returns the package name of the apk."""
+  return ApkHelper(apk_path).GetPackageName()
+
+
+# TODO(jbudorick): Deprecate and remove this function once callers have been
+# converted to ApkHelper.GetInstrumentationName
+def GetInstrumentationName(apk_path):
+  """Returns the name of the Instrumentation in the apk."""
+  return ApkHelper(apk_path).GetInstrumentationName()
+
+
+def ToHelper(path_or_helper):
+  """Creates an ApkHelper unless one is already given."""
+  if isinstance(path_or_helper, basestring):
+    return ApkHelper(path_or_helper)
+  return path_or_helper
+
+
+def _ParseManifestFromApk(apk_path):
+  aapt_output = aapt.Dump('xmltree', apk_path, 'AndroidManifest.xml')
+
+  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) or m.group(3))
+      continue
+
+  return parsed_manifest
+
+
+class ApkHelper(object):
+  def __init__(self, path):
+    self._apk_path = path
+    self._manifest = None
+
+  @property
+  def path(self):
+    return self._apk_path
+
+  def GetActivityName(self):
+    """Returns the name of the Activity in the apk."""
+    manifest_info = self._GetManifest()
+    try:
+      activity = (
+          manifest_info['manifest']['application']['activity']
+              ['android:name'][0])
+    except KeyError:
+      return None
+    if '.' not in activity:
+      activity = '%s.%s' % (self.GetPackageName(), activity)
+    elif activity.startswith('.'):
+      activity = '%s%s' % (self.GetPackageName(), activity)
+    return activity
+
+  def GetInstrumentationName(
+      self, default='android.test.InstrumentationTestRunner'):
+    """Returns the name of the Instrumentation in the apk."""
+    manifest_info = self._GetManifest()
+    try:
+      return manifest_info['manifest']['instrumentation']['android:name'][0]
+    except KeyError:
+      return default
+
+  def GetPackageName(self):
+    """Returns the package name of the apk."""
+    manifest_info = self._GetManifest()
+    try:
+      return manifest_info['manifest']['package'][0]
+    except KeyError:
+      raise Exception('Failed to determine package name of %s' % self._apk_path)
+
+  def GetPermissions(self):
+    manifest_info = self._GetManifest()
+    try:
+      return manifest_info['manifest']['uses-permission']['android:name']
+    except KeyError:
+      return []
+
+  def GetSplitName(self):
+    """Returns the name of the split of the apk."""
+    manifest_info = self._GetManifest()
+    try:
+      return manifest_info['manifest']['split'][0]
+    except KeyError:
+      return None
+
+  def HasIsolatedProcesses(self):
+    """Returns whether any services exist that use isolatedProcess=true."""
+    manifest_info = self._GetManifest()
+    try:
+      services = manifest_info['manifest']['application']['service']
+      return any(int(v, 0) for v in services['android:isolatedProcess'])
+    except KeyError:
+      return False
+
+  def _GetManifest(self):
+    if not self._manifest:
+      self._manifest = _ParseManifestFromApk(self._apk_path)
+    return self._manifest
+
diff --git a/build/android/devil/android/battery_utils.py b/build/android/devil/android/battery_utils.py
new file mode 100644
index 0000000..10dc49a
--- /dev/null
+++ b/build/android/devil/android/battery_utils.py
@@ -0,0 +1,630 @@
+# Copyright 2015 The Chromium 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 devil.android import decorators
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.android.sdk import version_codes
+from devil.utils import timeout_retry
+
+_DEFAULT_TIMEOUT = 30
+_DEFAULT_RETRIES = 3
+
+
+_DEVICE_PROFILES = [
+  {
+    'name': 'Nexus 4',
+    'witness_file': '/sys/module/pm8921_charger/parameters/disabled',
+    'enable_command': (
+        'echo 0 > /sys/module/pm8921_charger/parameters/disabled && '
+        'dumpsys battery reset'),
+    'disable_command': (
+        'echo 1 > /sys/module/pm8921_charger/parameters/disabled && '
+        'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
+    'charge_counter': None,
+    'voltage': None,
+    'current': None,
+  },
+  {
+    'name': 'Nexus 5',
+    # 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 && '
+        'chmod 644 /sys/class/power_supply/usb/online && '
+        'echo 1 > /sys/class/power_supply/usb/online && '
+        'dumpsys battery reset'),
+    '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 && '
+        'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
+    'charge_counter': None,
+    'voltage': None,
+    'current': None,
+  },
+  {
+    'name': 'Nexus 6',
+    'witness_file': None,
+    'enable_command': (
+        'echo 1 > /sys/class/power_supply/battery/charging_enabled && '
+        'dumpsys battery reset'),
+    'disable_command': (
+        'echo 0 > /sys/class/power_supply/battery/charging_enabled && '
+        'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
+    'charge_counter': (
+        '/sys/class/power_supply/max170xx_battery/charge_counter_ext'),
+    'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now',
+    'current': '/sys/class/power_supply/max170xx_battery/current_now',
+  },
+  {
+    'name': 'Nexus 9',
+    'witness_file': None,
+    'enable_command': (
+        'echo Disconnected > '
+        '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && '
+        'dumpsys battery reset'),
+    'disable_command': (
+        'echo Connected > '
+        '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && '
+        'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
+    'charge_counter': '/sys/class/power_supply/battery/charge_counter_ext',
+    'voltage': '/sys/class/power_supply/battery/voltage_now',
+    'current': '/sys/class/power_supply/battery/current_now',
+  },
+  {
+    'name': 'Nexus 10',
+    'witness_file': None,
+    'enable_command': None,
+    'disable_command': None,
+    'charge_counter': None,
+    'voltage': '/sys/class/power_supply/ds2784-fuelgauge/voltage_now',
+    'current': '/sys/class/power_supply/ds2784-fuelgauge/current_now',
+
+  },
+]
+
+# 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 consumption since last
+# charge are of interest here.
+_PWI_AGGREGATION_INDEX = 2
+_PWS_AGGREGATION_INDEX = _PWI_AGGREGATION_INDEX
+# The column containing the amount of power used, in mah.
+_PWI_POWER_CONSUMPTION_INDEX = 5
+_PWS_POWER_CONSUMPTION_INDEX = _PWI_POWER_CONSUMPTION_INDEX
+
+
+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 SupportsFuelGauge(self, timeout=None, retries=None):
+    """Detect if fuel gauge chip is present.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      True if known fuel gauge files are present.
+      False otherwise.
+    """
+    self._DiscoverDeviceProfile()
+    return (self._cache['profile']['enable_command'] != None
+        and self._cache['profile']['charge_counter'] != None)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetFuelGaugeChargeCounter(self, timeout=None, retries=None):
+    """Get value of charge_counter on fuel gauge chip.
+
+    Device must have charging disabled for this, not just battery updates
+    disabled. The only device that this currently works with is the nexus 5.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      value of charge_counter for fuel gauge chip in units of nAh.
+
+    Raises:
+      device_errors.CommandFailedError: If fuel gauge chip not found.
+    """
+    if self.SupportsFuelGauge():
+       return int(self._device.ReadFile(
+          self._cache['profile']['charge_counter']))
+    raise device_errors.CommandFailedError(
+        'Unable to find fuel gauge.')
+
+  @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 containing system power, and a per-package power dict keyed on
+      package names.
+      {
+        'system_total': 23.1,
+        'per_package' : {
+          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, large_output=True)
+    csvreader = csv.reader(dumpsys_output)
+    pwi_entries = collections.defaultdict(list)
+    system_total = None
+    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 different 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]))
+      elif (_PWS_POWER_CONSUMPTION_INDEX < len(entry)
+          and entry[_ROW_TYPE_INDEX] == 'pws'
+          and entry[_PWS_AGGREGATION_INDEX] == 'l'):
+        # This entry should only appear once.
+        assert system_total is None
+        system_total = float(entry[_PWS_POWER_CONSUMPTION_INDEX])
+
+    per_package = {p: {'uid': uid, 'data': pwi_entries[uid]}
+                   for p, uid in self._cache['uids'].iteritems()}
+    return {'system_total': system_total, 'per_package': per_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
+
+  # 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
+
+    self._ClearPowerData()
+    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()
+              or not bool('UPDATES STOPPED' in self._device.RunShellCommand(
+                  ['dumpsys', 'battery'], check_return=True)))
+
+    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 < 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 _DischargeDevice(self, percent, wait_period=120):
+    """Disables charging and waits for device to discharge given amount
+
+    Args:
+      percent: level of charge to discharge.
+
+    Raises:
+      ValueError: If percent is not between 1 and 99.
+    """
+    battery_level = int(self.GetBatteryInfo().get('level'))
+    if not 0 < percent < 100:
+      raise ValueError('Discharge amount(%s) must be between 1 and 99'
+                       % percent)
+    if battery_level is None:
+      logging.warning('Unable to find current battery level. Cannot discharge.')
+      return
+    # Do not discharge if it would make battery level too low.
+    if percent >= battery_level - 10:
+      logging.warning('Battery is too low or discharge amount requested is too '
+                      'high. Cannot discharge phone %s percent.', percent)
+      return
+
+    self._HardwareSetCharging(False)
+    def device_discharged():
+      self._HardwareSetCharging(True)
+      current_level = int(self.GetBatteryInfo().get('level'))
+      logging.info('current battery level: %s', current_level)
+      if battery_level - current_level >= percent:
+        return True
+      self._HardwareSetCharging(False)
+      return False
+
+    timeout_retry.WaitFor(device_discharged, wait_period=wait_period)
+
+  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=180):
+    """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)
+      if int(temp) <= target_temp:
+        return True
+      else:
+        if self._cache['profile']['name'] == 'Nexus 5':
+          self._DischargeDevice(1)
+        return False
+
+    self._DiscoverDeviceProfile()
+    self.EnableBatteryUpdates()
+    logging.info('Waiting for the device to cool down to %s (0.1 C)',
+                 target_temp)
+    timeout_retry.WaitFor(cool_device, wait_period=wait_period)
+
+  @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
+    """
+    if self.GetCharging() == enabled:
+      logging.warning('Device charging already in expected state: %s', enabled)
+      return
+
+    self._DiscoverDeviceProfile()
+    if enabled:
+      if self._cache['profile']['enable_command']:
+        self._HardwareSetCharging(enabled)
+      else:
+        logging.info('Unable to enable charging via hardware. '
+                     'Falling back to software enabling.')
+        self.EnableBatteryUpdates()
+    else:
+      if self._cache['profile']['enable_command']:
+        self._ClearPowerData()
+        self._HardwareSetCharging(enabled)
+      else:
+        logging.info('Unable to disable charging via hardware. '
+                     'Falling back to software disabling.')
+        self.DisableBatteryUpdates()
+
+  def _HardwareSetCharging(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.
+    """
+    self._DiscoverDeviceProfile()
+    if not self._cache['profile']['enable_command']:
+      raise device_errors.CommandFailedError(
+          'Unable to find charging commands.')
+
+    command = (self._cache['profile']['enable_command'] if enabled
+               else self._cache['profile']['disable_command'])
+
+    def verify_charging():
+      return self.GetCharging() == enabled
+
+    self._device.RunShellCommand(
+        command, check_return=True, as_root=True, large_output=True)
+    timeout_retry.WaitFor(verify_charging, wait_period=1)
+
+  @contextlib.contextmanager
+  def PowerMeasurement(self, timeout=None, retries=None):
+    """Context manager that enables battery power collection.
+
+    Once the with block is exited, charging is resumed. Will attempt to disable
+    charging at the hardware level, and if that fails will fall back to software
+    disabling of battery updates.
+
+    Only for devices L and higher.
+
+    Example usage:
+      with PowerMeasurement():
+        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
+    """
+    try:
+      self.SetCharging(False, timeout=timeout, retries=retries)
+      yield
+    finally:
+      self.SetCharging(True, timeout=timeout, retries=retries)
+
+  def _ClearPowerData(self):
+    """Resets battery data and makes device appear like it is not
+    charging so that it will collect power data since last charge.
+
+    Returns:
+      True if power data cleared.
+      False if power data clearing is not supported (pre-L)
+
+    Raises:
+      device_errors.DeviceVersionError: If power clearing is supported,
+        but fails.
+    """
+    if self._device.build_version_sdk < version_codes.LOLLIPOP:
+      logging.warning('Dumpsys power data only available on 5.0 and above. '
+                      'Cannot clear power data.')
+      return False
+
+    self._device.RunShellCommand(
+        ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True)
+    self._device.RunShellCommand(
+        ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True)
+    self._device.RunShellCommand(
+        ['dumpsys', 'batterystats', '--reset'], check_return=True)
+    battery_data = self._device.RunShellCommand(
+        ['dumpsys', 'batterystats', '--charged', '-c'],
+        check_return=True, large_output=True)
+    for line in battery_data:
+      l = line.split(',')
+      if (len(l) > _PWI_POWER_CONSUMPTION_INDEX and l[_ROW_TYPE_INDEX] == 'pwi'
+          and l[_PWI_POWER_CONSUMPTION_INDEX] != 0):
+        self._device.RunShellCommand(
+            ['dumpsys', 'battery', 'reset'], check_return=True)
+        raise device_errors.CommandFailedError(
+            'Non-zero pmi value found after reset.')
+    self._device.RunShellCommand(
+        ['dumpsys', 'battery', 'reset'], check_return=True)
+    return True
+
+  def _DiscoverDeviceProfile(self):
+    """Checks and caches device information.
+
+    Returns:
+      True if profile is found, false otherwise.
+    """
+
+    if 'profile' in self._cache:
+      return True
+    for profile in _DEVICE_PROFILES:
+      if self._device.product_model == profile['name']:
+        self._cache['profile'] = profile
+        return True
+    self._cache['profile'] = {
+        'name': None,
+        'witness_file': None,
+        'enable_command': None,
+        'disable_command': None,
+        'charge_counter': None,
+        'voltage': None,
+        'current': None,
+    }
+    return False
diff --git a/build/android/devil/android/battery_utils_test.py b/build/android/devil/android/battery_utils_test.py
new file mode 100755
index 0000000..af18e89
--- /dev/null
+++ b/build/android/devil/android/battery_utils_test.py
@@ -0,0 +1,646 @@
+#!/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=protected-access,unused-argument
+
+import logging
+import os
+import sys
+import unittest
+
+from devil.android import battery_utils
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.android import device_utils_test
+from devil.utils import mock_calls
+from pylib import constants
+
+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',
+    '9,0,l,pws,1728,2000,190,207',
+]
+
+
+class BatteryUtilsTest(mock_calls.TestCase):
+
+  _NEXUS_5 = {
+    'name': 'Nexus 5',
+    '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'),
+    'charge_counter': None,
+    'voltage': None,
+    'current': None,
+  }
+
+  _NEXUS_6 = {
+    'name': 'Nexus 6',
+    'witness_file': None,
+    'enable_command': None,
+    'disable_command': None,
+    'charge_counter': (
+        '/sys/class/power_supply/max170xx_battery/charge_counter_ext'),
+    'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now',
+    'current': '/sys/class/power_supply/max170xx_battery/current_now',
+  }
+
+  _NEXUS_10 = {
+    'name': 'Nexus 10',
+    'witness_file': None,
+    'enable_command': None,
+    'disable_command': None,
+    'charge_counter': (
+        '/sys/class/power_supply/ds2784-fuelgauge/charge_counter_ext'),
+    'voltage': '/sys/class/power_supply/ds2784-fuelgauge/voltage_now',
+    'current': '/sys/class/power_supply/ds2784-fuelgauge/current_now',
+  }
+
+  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 testHardwareSetCharging_enabled(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            mock.ANY, check_return=True, as_root=True, large_output=True), []),
+        (self.call.battery.GetCharging(), False),
+        (self.call.battery.GetCharging(), True)):
+      self.battery._HardwareSetCharging(True)
+
+  def testHardwareSetCharging_alreadyEnabled(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            mock.ANY, check_return=True, as_root=True, large_output=True), []),
+        (self.call.battery.GetCharging(), True)):
+      self.battery._HardwareSetCharging(True)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testHardwareSetCharging_disabled(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            mock.ANY, check_return=True, as_root=True, large_output=True), []),
+        (self.call.battery.GetCharging(), True),
+        (self.call.battery.GetCharging(), False)):
+      self.battery._HardwareSetCharging(False)
+
+
+class BatteryUtilsSetBatteryMeasurementTest(BatteryUtilsTest):
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testBatteryMeasurementWifi(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=22):
+      with self.assertCalls(
+          (self.call.battery._ClearPowerData(), 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(), False),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
+          (self.call.battery.GetCharging(), False),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'battery'], check_return=True), [])):
+        with self.battery.BatteryMeasurement():
+          pass
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testBatteryMeasurementUsb(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=22):
+      with self.assertCalls(
+          (self.call.battery._ClearPowerData(), 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(), False),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
+          (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, large_output=True),
+         _DUMPSYS_OUTPUT)):
+      data = self.battery.GetPowerData()
+      check = {
+        'system_total': 2000.0,
+        'per_package': {
+          '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, large_output=True),
+          _DUMPSYS_OUTPUT):
+        data = self.battery.GetPowerData()
+        check = {
+          'system_total': 2000.0,
+          'per_package': {
+            '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, large_output=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, large_output=True),
+         _DUMPSYS_OUTPUT)):
+      self.battery._cache.clear()
+      data = self.battery.GetPowerData()
+      check = {
+        'system_total': 2000.0,
+        'per_package': {
+          'test_package1': {'uid': '1000', 'data': [1.0]},
+          'test_package2': {'uid': '1001', 'data': [2.0]}
+        }
+      }
+      self.assertEqual(data, check)
+
+
+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 BatteryUtilsDischargeDevice(BatteryUtilsTest):
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testDischargeDevice_exact(self):
+    with self.assertCalls(
+        (self.call.battery.GetBatteryInfo(), {'level': '100'}),
+        (self.call.battery._HardwareSetCharging(False)),
+        (self.call.battery._HardwareSetCharging(True)),
+        (self.call.battery.GetBatteryInfo(), {'level': '99'})):
+      self.battery._DischargeDevice(1)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testDischargeDevice_over(self):
+    with self.assertCalls(
+        (self.call.battery.GetBatteryInfo(), {'level': '100'}),
+        (self.call.battery._HardwareSetCharging(False)),
+        (self.call.battery._HardwareSetCharging(True)),
+        (self.call.battery.GetBatteryInfo(), {'level': '50'})):
+      self.battery._DischargeDevice(1)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testDischargeDevice_takeslong(self):
+    with self.assertCalls(
+        (self.call.battery.GetBatteryInfo(), {'level': '100'}),
+        (self.call.battery._HardwareSetCharging(False)),
+        (self.call.battery._HardwareSetCharging(True)),
+        (self.call.battery.GetBatteryInfo(), {'level': '100'}),
+        (self.call.battery._HardwareSetCharging(False)),
+        (self.call.battery._HardwareSetCharging(True)),
+        (self.call.battery.GetBatteryInfo(), {'level': '99'}),
+        (self.call.battery._HardwareSetCharging(False)),
+        (self.call.battery._HardwareSetCharging(True)),
+        (self.call.battery.GetBatteryInfo(), {'level': '98'}),
+        (self.call.battery._HardwareSetCharging(False)),
+        (self.call.battery._HardwareSetCharging(True)),
+        (self.call.battery.GetBatteryInfo(), {'level': '97'})):
+      self.battery._DischargeDevice(3)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testDischargeDevice_dischargeTooClose(self):
+    with self.assertCalls(
+        (self.call.battery.GetBatteryInfo(), {'level': '100'})):
+      self.battery._DischargeDevice(99)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testDischargeDevice_percentageOutOfBounds(self):
+    with self.assertCalls(
+        (self.call.battery.GetBatteryInfo(), {'level': '100'})):
+      with self.assertRaises(ValueError):
+          self.battery._DischargeDevice(100)
+    with self.assertCalls(
+        (self.call.battery.GetBatteryInfo(), {'level': '100'})):
+      with self.assertRaises(ValueError):
+          self.battery._DischargeDevice(0)
+
+
+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, large_output=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, large_output=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, large_output=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, large_output=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):
+    self.battery._cache['profile'] = self._NEXUS_6
+    with self.assertCalls(
+        (self.call.battery.EnableBatteryUpdates(), []),
+        (self.call.battery.GetBatteryInfo(), {'temperature': '500'})):
+      self.battery.LetBatteryCoolToTemperature(600)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testLetBatteryCoolToTemperature_startOver(self):
+    self.battery._cache['profile'] = self._NEXUS_6
+    with self.assertCalls(
+        (self.call.battery.EnableBatteryUpdates(), []),
+        (self.call.battery.GetBatteryInfo(), {'temperature': '500'}),
+        (self.call.battery.GetBatteryInfo(), {'temperature': '400'})):
+      self.battery.LetBatteryCoolToTemperature(400)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testLetBatteryCoolToTemperature_nexus5Hot(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    with self.assertCalls(
+        (self.call.battery.EnableBatteryUpdates(), []),
+        (self.call.battery.GetBatteryInfo(), {'temperature': '500'}),
+        (self.call.battery._DischargeDevice(1), []),
+        (self.call.battery.GetBatteryInfo(), {'temperature': '400'})):
+      self.battery.LetBatteryCoolToTemperature(400)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testLetBatteryCoolToTemperature_nexus5Cool(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    with self.assertCalls(
+        (self.call.battery.EnableBatteryUpdates(), []),
+        (self.call.battery.GetBatteryInfo(), {'temperature': '400'})):
+      self.battery.LetBatteryCoolToTemperature(400)
+
+
+class BatteryUtilsSupportsFuelGaugeTest(BatteryUtilsTest):
+
+  def testSupportsFuelGauge_false(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    self.assertFalse(self.battery.SupportsFuelGauge())
+
+  def testSupportsFuelGauge_trueMax(self):
+    self.battery._cache['profile'] = self._NEXUS_6
+    # TODO(rnephew): Change this to assertTrue when we have support for
+    # disabling hardware charging on nexus 6.
+    self.assertFalse(self.battery.SupportsFuelGauge())
+
+  def testSupportsFuelGauge_trueDS(self):
+    self.battery._cache['profile'] = self._NEXUS_10
+    # TODO(rnephew): Change this to assertTrue when we have support for
+    # disabling hardware charging on nexus 10.
+    self.assertFalse(self.battery.SupportsFuelGauge())
+
+
+class BatteryUtilsGetFuelGaugeChargeCounterTest(BatteryUtilsTest):
+
+  def testGetFuelGaugeChargeCounter_noFuelGauge(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    with self.assertRaises(device_errors.CommandFailedError):
+        self.battery.GetFuelGaugeChargeCounter()
+
+  def testGetFuelGaugeChargeCounter_fuelGaugePresent(self):
+    self.battery._cache['profile'] = self._NEXUS_6
+    with self.assertCalls(
+        (self.call.battery.SupportsFuelGauge(), True),
+        (self.call.device.ReadFile(mock.ANY), '123')):
+      self.assertEqual(self.battery.GetFuelGaugeChargeCounter(), 123)
+
+
+class BatteryUtilsSetCharging(BatteryUtilsTest):
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetCharging_softwareSetTrue(self):
+    self.battery._cache['profile'] = self._NEXUS_6
+    with self.assertCalls(
+        (self.call.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'reset'], check_return=True), []),
+        (self.call.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
+        (self.call.battery.GetCharging(), True)):
+      self.battery.SetCharging(True)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetCharging_softwareSetFalse(self):
+    self.battery._cache['profile'] = self._NEXUS_6
+    with self.assertCalls(
+        (self.call.battery.GetCharging(), True),
+        (self.call.battery._ClearPowerData(), 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.battery.SetCharging(False)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetCharging_hardwareSetTrue(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    with self.assertCalls(
+        (self.call.battery.GetCharging(), False),
+        (self.call.battery._HardwareSetCharging(True))):
+      self.battery.SetCharging(True)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetCharging_hardwareSetFalse(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    with self.assertCalls(
+        (self.call.battery.GetCharging(), True),
+        (self.call.battery._ClearPowerData(), True),
+        (self.call.battery._HardwareSetCharging(False))):
+      self.battery.SetCharging(False)
+
+  def testSetCharging_expectedStateAlreadyTrue(self):
+    with self.assertCalls((self.call.battery.GetCharging(), True)):
+      self.battery.SetCharging(True)
+
+  def testSetCharging_expectedStateAlreadyFalse(self):
+    with self.assertCalls((self.call.battery.GetCharging(), False)):
+      self.battery.SetCharging(False)
+
+
+class BatteryUtilsPowerMeasurement(BatteryUtilsTest):
+
+  def testPowerMeasurement_hardware(self):
+    self.battery._cache['profile'] = self._NEXUS_5
+    with self.assertCalls(
+        (self.call.battery.GetCharging(), True),
+        (self.call.battery._ClearPowerData(), True),
+        (self.call.battery._HardwareSetCharging(False)),
+        (self.call.battery.GetCharging(), False),
+        (self.call.battery._HardwareSetCharging(True))):
+      with self.battery.PowerMeasurement():
+        pass
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testPowerMeasurement_software(self):
+    self.battery._cache['profile'] = self._NEXUS_6
+    with self.assertCalls(
+        (self.call.battery.GetCharging(), True),
+        (self.call.battery._ClearPowerData(), 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.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'reset'], check_return=True), []),
+        (self.call.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
+        (self.call.battery.GetCharging(), True)):
+      with self.battery.PowerMeasurement():
+        pass
+
+
+class BatteryUtilsDiscoverDeviceProfile(BatteryUtilsTest):
+
+  def testDiscoverDeviceProfile_known(self):
+    with self.patch_call(self.call.device.product_model,
+                         return_value='Nexus 4'):
+      self.battery._DiscoverDeviceProfile()
+      self.assertEqual(self.battery._cache['profile']['name'], "Nexus 4")
+
+  def testDiscoverDeviceProfile_unknown(self):
+    with self.patch_call(self.call.device.product_model,
+                         return_value='Other'):
+      self.battery._DiscoverDeviceProfile()
+      self.assertEqual(self.battery._cache['profile']['name'], None)
+
+
+class BatteryUtilsClearPowerData(BatteryUtilsTest):
+
+  def testClearPowerData_preL(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=20):
+      self.assertFalse(self.battery._ClearPowerData())
+
+  def testClearPowerData_clearedL(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=22):
+      with self.assertCalls(
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True),
+           []),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True), []),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'batterystats', '--charged', '-c'],
+              check_return=True, large_output=True), []),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'battery', 'reset'], check_return=True), [])):
+        self.assertTrue(self.battery._ClearPowerData())
+
+  def testClearPowerData_notClearedL(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=22):
+      with self.assertCalls(
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True),
+           []),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True), []),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'batterystats', '--charged', '-c'],
+              check_return=True, large_output=True),
+              ['9,1000,l,pwi,uid,0.0327']),
+          (self.call.device.RunShellCommand(
+              ['dumpsys', 'battery', 'reset'], check_return=True), [])):
+        with self.assertRaises(device_errors.CommandFailedError):
+          self.battery._ClearPowerData()
+
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
diff --git a/build/android/devil/android/decorators.py b/build/android/devil/android/decorators.py
new file mode 100644
index 0000000..b263790
--- /dev/null
+++ b/build/android/devil/android/decorators.py
@@ -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.
+
+"""
+Function/method decorators that provide timeout and retry logic.
+"""
+
+import functools
+import itertools
+import sys
+
+from devil.android import device_errors
+from devil.utils import cmd_helper
+from devil.utils import reraiser_thread
+from devil.utils import timeout_retry
+
+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 timeout_retry_wrapper(*args, **kwargs):
+    timeout = timeout_func(*args, **kwargs)
+    retries = retries_func(*args, **kwargs)
+    if pass_values:
+      kwargs['timeout'] = timeout
+      kwargs['retries'] = retries
+    @functools.wraps(f)
+    def impl():
+      return f(*args, **kwargs)
+    try:
+      if timeout_retry.CurrentTimeoutThreadGroup():
+        # Don't wrap if there's already an outer timeout thread.
+        return impl()
+      else:
+        desc = '%s(%s)' % (f.__name__, ', '.join(itertools.chain(
+            (str(a) for a in args),
+            ('%s=%s' % (k, str(v)) for k, v in kwargs.iteritems()))))
+        return timeout_retry.Run(impl, timeout, retries, desc=desc)
+    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 timeout_retry_wrapper
+
+
+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,
+    min_default_timeout=None):
+  """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.
+    min_timeout: Miniumum timeout to be used when using instance timeout.
+  Returns:
+    The actual decorator.
+  """
+  def decorator(f):
+    def get_timeout(inst, *_args, **kwargs):
+      ret = getattr(inst, default_timeout_name)
+      if min_default_timeout is not None:
+        ret = max(min_default_timeout, ret)
+      return kwargs.get('timeout', ret)
+    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/devil/android/decorators_test.py
similarity index 75%
rename from build/android/pylib/device/decorators_test.py
rename to build/android/devil/android/decorators_test.py
index b75618b..1b6179e 100644
--- a/build/android/pylib/device/decorators_test.py
+++ b/build/android/devil/android/decorators_test.py
@@ -8,22 +8,13 @@
 
 # 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
+from devil.android import decorators
+from devil.android import device_errors
+from devil.utils import reraiser_thread
 
 _DEFAULT_TIMEOUT = 30
 _DEFAULT_RETRIES = 3
@@ -78,26 +69,6 @@
     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
@@ -166,24 +137,6 @@
     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)
@@ -223,24 +176,6 @@
       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)
@@ -288,6 +223,11 @@
       return timeout
 
     @decorators.WithTimeoutAndRetriesFromInstance(
+        'default_timeout', 'default_retries', min_default_timeout=100)
+    def alwaysReturnsTimeoutWithMin(self, timeout=None, retries=None):
+      return timeout
+
+    @decorators.WithTimeoutAndRetriesFromInstance(
         'default_timeout', 'default_retries')
     def alwaysReturnsRetries(self, timeout=None, retries=None):
       return retries
@@ -336,20 +276,11 @@
     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 testMethodDecoratorUsesMiniumumTimeout(self):
+    test_obj = self._MethodDecoratorTestObject(
+        self, default_timeout=42, default_retries=31)
+    self.assertEquals(100, test_obj.alwaysReturnsTimeoutWithMin())
+    self.assertEquals(41, test_obj.alwaysReturnsTimeoutWithMin(timeout=41))
 
   def testMethodDecoratorTranslatesReraiserExceptions(self):
     test_obj = self._MethodDecoratorTestObject(self)
diff --git a/build/android/devil/android/device_blacklist.py b/build/android/devil/android/device_blacklist.py
new file mode 100644
index 0000000..a38da15
--- /dev/null
+++ b/build/android/devil/android/device_blacklist.py
@@ -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.
+
+import json
+import logging
+import os
+import threading
+import time
+
+from pylib import constants
+
+# TODO(jbudorick): Remove this once the blacklist is optional.
+BLACKLIST_JSON = os.path.join(
+    constants.DIR_SOURCE_ROOT,
+    os.environ.get('CHROMIUM_OUT_DIR', 'out'),
+    'bad_devices.json')
+
+class Blacklist(object):
+
+  def __init__(self, path):
+    self._blacklist_lock = threading.RLock()
+    self._path = path
+
+  def Read(self):
+    """Reads the blacklist from the blacklist file.
+
+    Returns:
+      A dict containing bad devices.
+    """
+    with self._blacklist_lock:
+      if not os.path.exists(self._path):
+        return dict()
+
+      with open(self._path, 'r') as f:
+        blacklist = json.load(f)
+      if not isinstance(blacklist, dict):
+        logging.warning('Ignoring %s: %s (a dict was expected instead)',
+                        self._path, blacklist)
+        blacklist = dict()
+      return blacklist
+
+  def Write(self, blacklist):
+    """Writes the provided blacklist to the blacklist file.
+
+    Args:
+      blacklist: list of bad devices to write to the blacklist file.
+    """
+    with self._blacklist_lock:
+      with open(self._path, 'w') as f:
+        json.dump(blacklist, f)
+
+  def Extend(self, devices, reason='unknown'):
+    """Adds devices to blacklist file.
+
+    Args:
+      devices: list of bad devices to be added to the blacklist file.
+      reason: string specifying the reason for blacklist (eg: 'unauthorized')
+    """
+    timestamp = time.time()
+    event_info = {
+        'timestamp': timestamp,
+        'reason': reason,
+    }
+    device_dicts = {device: event_info for device in devices}
+    logging.info('Adding %s to blacklist %s for reason: %s',
+                 ','.join(devices), self._path, reason)
+    with self._blacklist_lock:
+      blacklist = self.Read()
+      blacklist.update(device_dicts)
+      self.Write(blacklist)
+
+  def Reset(self):
+    """Erases the blacklist file if it exists."""
+    logging.info('Resetting blacklist %s', self._path)
+    with self._blacklist_lock:
+      if os.path.exists(self._path):
+        os.remove(self._path)
diff --git a/build/android/devil/android/device_errors.py b/build/android/devil/android/device_errors.py
new file mode 100644
index 0000000..ef6e3a9
--- /dev/null
+++ b/build/android/devil/android/device_errors.py
@@ -0,0 +1,108 @@
+# Copyright 2014 The Chromium 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 devil import base_error
+from devil.utils import cmd_helper
+
+
+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 _BaseCommandFailedError(CommandFailedError):
+  """Base Exception for adb and fastboot 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(_BaseCommandFailedError, self).__init__(message, device_serial)
+
+class AdbCommandFailedError(_BaseCommandFailedError):
+  """Exception for adb command failures."""
+
+  def __init__(self, args, output, status=None, device_serial=None,
+               message=None):
+    super(AdbCommandFailedError, self).__init__(
+        args, output, status=status, message=message,
+        device_serial=device_serial)
+
+
+class FastbootCommandFailedError(_BaseCommandFailedError):
+  """Exception for fastboot command failures."""
+
+  def __init__(self, args, output, status=None, device_serial=None,
+               message=None):
+    super(FastbootCommandFailedError, self).__init__(
+        args, output, status=status, message=message,
+        device_serial=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/devil/android/device_list.py b/build/android/devil/android/device_list.py
new file mode 100644
index 0000000..0eb6acb
--- /dev/null
+++ b/build/android/devil/android/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/devil/android/device_signal.py b/build/android/devil/android/device_signal.py
new file mode 100644
index 0000000..6a5b709
--- /dev/null
+++ b/build/android/devil/android/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/devil/android/device_temp_file.py b/build/android/devil/android/device_temp_file.py
new file mode 100644
index 0000000..af2c489
--- /dev/null
+++ b/build/android/devil/android/device_temp_file.py
@@ -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.
+
+"""A temp file that automatically gets pushed and deleted from a device."""
+
+# pylint: disable=W0622
+
+import posixpath
+import random
+import threading
+
+from devil.android import device_errors
+from devil.utils import cmd_helper
+
+
+class DeviceTempFile(object):
+  def __init__(self, adb, suffix='', prefix='temp_file', dir='/data/local/tmp'):
+    """Find an unused temporary file path on the device.
+
+    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
+    # Python's random module use 52-bit numbers according to its docs.
+    random_hex = hex(random.randint(0, 2 ** 52))[2:]
+    self.name = posixpath.join(dir, '%s-%s%s' % (prefix, random_hex, suffix))
+    self.name_quoted = cmd_helper.SingleQuote(self.name)
+
+  def close(self):
+    """Deletes the temporary file from the device."""
+    # ignore exception if the file is already gone.
+    def delete_temporary_file():
+      try:
+        self._adb.Shell('rm -f %s' % self.name_quoted, expect_status=None)
+      except device_errors.AdbCommandFailedError:
+        # file does not exist on Android version without 'rm -f' support (ICS)
+        pass
+
+    # It shouldn't matter when the temp file gets deleted, so do so
+    # asynchronously.
+    threading.Thread(
+        target=delete_temporary_file,
+        name='delete_temporary_file(%s)' % self._adb.GetDeviceSerial()).start()
+
+  def __enter__(self):
+    return self
+
+  def __exit__(self, type, value, traceback):
+    self.close()
diff --git a/build/android/devil/android/device_utils.py b/build/android/devil/android/device_utils.py
new file mode 100644
index 0000000..aee5d7c
--- /dev/null
+++ b/build/android/devil/android/device_utils.py
@@ -0,0 +1,2137 @@
+# Copyright 2014 The Chromium 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 itertools
+import json
+import logging
+import multiprocessing
+import os
+import posixpath
+import re
+import shutil
+import tempfile
+import time
+import zipfile
+
+from devil import base_error
+from devil.utils import cmd_helper
+from devil.android import apk_helper
+from devil.android import device_signal
+from devil.android import decorators
+from devil.android import device_errors
+from devil.android import device_temp_file
+from devil.android import logcat_monitor
+from devil.android import md5sum
+from devil.android.sdk import adb_wrapper
+from devil.android.sdk import intent
+from devil.android.sdk import keyevent
+from devil.android.sdk import split_select
+from devil.android.sdk import version_codes
+from devil.utils import host_utils
+from devil.utils import parallelizer
+from devil.utils import reraiser_thread
+from devil.utils import timeout_retry
+from devil.utils import zip_utils
+from pylib import constants
+from pylib.device.commands import install_commands
+
+_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()
+
+_RESTART_ADBD_SCRIPT = """
+  trap '' HUP
+  trap '' TERM
+  trap '' PIPE
+  function restart() {
+    stop adbd
+    start adbd
+  }
+  restart &
+"""
+
+# Not all permissions can be set.
+_PERMISSIONS_BLACKLIST = [
+    'android.permission.ACCESS_MOCK_LOCATION',
+    'android.permission.ACCESS_NETWORK_STATE',
+    'android.permission.BLUETOOTH',
+    'android.permission.BLUETOOTH_ADMIN',
+    'android.permission.DOWNLOAD_WITHOUT_NOTIFICATION',
+    'android.permission.INTERNET',
+    'android.permission.MANAGE_ACCOUNTS',
+    'android.permission.MODIFY_AUDIO_SETTINGS',
+    'android.permission.NFC',
+    'android.permission.READ_SYNC_SETTINGS',
+    'android.permission.READ_SYNC_STATS',
+    'android.permission.USE_CREDENTIALS',
+    'android.permission.VIBRATE',
+    'android.permission.WAKE_LOCK',
+    'android.permission.WRITE_SYNC_SETTINGS',
+    'com.android.browser.permission.READ_HISTORY_BOOKMARKS',
+    'com.android.browser.permission.WRITE_HISTORY_BOOKMARKS',
+    'com.android.launcher.permission.INSTALL_SHORTCUT',
+    'com.chrome.permission.DEVICE_EXTRAS',
+    'com.google.android.apps.chrome.permission.C2D_MESSAGE',
+    'com.google.android.apps.chrome.permission.READ_WRITE_BOOKMARK_FOLDERS',
+    'com.google.android.apps.chrome.TOS_ACKED',
+    'com.google.android.c2dm.permission.RECEIVE',
+    'com.google.android.providers.gsf.permission.READ_GSERVICES',
+    'com.sec.enterprise.knox.MDM_CONTENT_PROVIDER',
+]
+
+_CURRENT_FOCUS_CRASH_RE = re.compile(
+    r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}')
+
+_GETPROP_RE = re.compile(r'\[(.*?)\]: \[(.*?)\]')
+
+@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
+  _LAUNCHER_FOCUSED_RE = re.compile(
+      r'\s*mCurrentFocus.*(Launcher|launcher).*')
+  _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
+
+  LOCAL_PROPERTIES_PATH = posixpath.join('/', 'data', 'local.prop')
+
+  # Property in /data/local.prop that controls Java assertions.
+  JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions'
+
+  def __init__(self, device, enable_device_files_cache=False,
+               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.
+      enable_device_files_cache: For PushChangedFiles(), cache checksums of
+        pushed files rather than recomputing them on a subsequent call.
+      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
+    if isinstance(device, basestring):
+      self.adb = adb_wrapper.AdbWrapper(device)
+    elif isinstance(device, adb_wrapper.AdbWrapper):
+      self.adb = device
+    else:
+      raise ValueError('Unsupported device value: %r' % device)
+    self._commands_installed = None
+    self._default_timeout = default_timeout
+    self._default_retries = default_retries
+    self._enable_device_files_cache = enable_device_files_cache
+    self._cache = {}
+    self._client_caches = {}
+    assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)
+    assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR)
+
+    self._ClearCache()
+
+  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(
+            '%s && ! ls /root' % self._Su('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']
+
+  def _Su(self, command):
+    if self.build_version_sdk >= version_codes.MARSHMALLOW:
+      return 'su 0 %s' % command
+    return 'su -c %s' % command
+
+  @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.WaitUntilFullyBooted()
+
+  @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 GetApplicationPaths(self, package, timeout=None, retries=None):
+    """Get the paths of the installed apks on the device for the given package.
+
+    Args:
+      package: Name of the package.
+
+    Returns:
+      List of paths to the apks on the device for the given package.
+    """
+    return self._GetApplicationPathsInternal(package)
+
+  def _GetApplicationPathsInternal(self, package, skip_cache=False):
+    cached_result = self._cache['package_apk_paths'].get(package)
+    if cached_result is not None and not skip_cache:
+      if package in self._cache['package_apk_paths_to_verify']:
+        self._cache['package_apk_paths_to_verify'].remove(package)
+        # Don't verify an app that is not thought to be installed. We are
+        # concerned only with apps we think are installed having been
+        # uninstalled manually.
+        if cached_result and not self.PathExists(cached_result):
+          cached_result = None
+          self._cache['package_apk_checksums'].pop(package, 0)
+      if cached_result is not None:
+        return list(cached_result)
+    # '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 < version_codes.LOLLIPOP)
+    output = self.RunShellCommand(
+        ['pm', 'path', package], check_return=should_check_return)
+    apks = []
+    for line in output:
+      if not line.startswith('package:'):
+        raise device_errors.CommandFailedError(
+            'pm path returned: %r' % '\n'.join(output), str(self))
+      apks.append(line[len('package:'):])
+    self._cache['package_apk_paths'][package] = list(apks)
+    return apks
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetApplicationVersion(self, package, timeout=None, retries=None):
+    """Get the version name of a package installed on the device.
+
+    Args:
+      package: Name of the package.
+
+    Returns:
+      A string with the version name or None if the package is not found
+      on the device.
+    """
+    output = self.RunShellCommand(
+        ['dumpsys', 'package', package], check_return=True)
+    if not output:
+      return None
+    for line in output:
+      line = line.strip()
+      if line.startswith('versionName='):
+        return line[len('versionName='):]
+    raise device_errors.CommandFailedError(
+        'Version name for %s not found on dumpsys output' % package, str(self))
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetApplicationDataDirectory(self, package, timeout=None, retries=None):
+    """Get the data directory on the device for the given package.
+
+    Args:
+      package: Name of the package.
+
+    Returns:
+      The package's data directory, or None if the package doesn't exist on the
+      device.
+    """
+    try:
+      output = self._RunPipedShellCommand(
+          'pm dump %s | grep dataDir=' % cmd_helper.SingleQuote(package))
+      for line in output:
+        _, _, dataDir = line.partition('dataDir=')
+        if dataDir:
+          return dataDir
+    except device_errors.CommandFailedError:
+      logging.exception('Could not find data directory for %s', package)
+    return None
+
+  @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._GetApplicationPathsInternal('android', skip_cache=True)
+      except device_errors.CommandFailedError:
+        return False
+
+    def boot_completed():
+      return self.GetProp('sys.boot_completed', cache=False) == '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
+
+  @decorators.WithTimeoutAndRetriesFromInstance(
+      min_default_timeout=REBOOT_DEFAULT_TIMEOUT)
+  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
+
+  @decorators.WithTimeoutAndRetriesFromInstance(
+      min_default_timeout=INSTALL_DEFAULT_TIMEOUT)
+  def Install(self, apk, reinstall=False, permissions=None, timeout=None,
+              retries=None):
+    """Install an APK.
+
+    Noop if an identical APK is already installed.
+
+    Args:
+      apk: An ApkHelper instance or string containing the path to the APK.
+      permissions: Set of permissions to set. If not set, finds permissions with
+          apk helper. To set no permissions, pass [].
+      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.
+    """
+    self._InstallInternal(apk, None, reinstall=reinstall,
+                          permissions=permissions)
+
+  @decorators.WithTimeoutAndRetriesFromInstance(
+      min_default_timeout=INSTALL_DEFAULT_TIMEOUT)
+  def InstallSplitApk(self, base_apk, split_apks, reinstall=False,
+                      allow_cached_props=False, permissions=None, timeout=None,
+                      retries=None):
+    """Install a split APK.
+
+    Noop if all of the APK splits are already installed.
+
+    Args:
+      base_apk: An ApkHelper instance or string containing the path to the base
+          APK.
+      split_apks: A list of strings of paths of all of the APK splits.
+      reinstall: A boolean indicating if we should keep any existing app data.
+      allow_cached_props: Whether to use cached values for device properties.
+      permissions: Set of permissions to set. If not set, finds permissions with
+          apk helper. To set no permissions, pass [].
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandFailedError if the installation fails.
+      CommandTimeoutError if the installation times out.
+      DeviceUnreachableError on missing device.
+      DeviceVersionError if device SDK is less than Android L.
+    """
+    self._InstallInternal(base_apk, split_apks, reinstall=reinstall,
+                          allow_cached_props=allow_cached_props,
+                          permissions=permissions)
+
+  def _InstallInternal(self, base_apk, split_apks, reinstall=False,
+                       allow_cached_props=False, permissions=None):
+    if split_apks:
+      self._CheckSdkLevel(version_codes.LOLLIPOP)
+
+    base_apk = apk_helper.ToHelper(base_apk)
+
+    all_apks = [base_apk.path]
+    if split_apks:
+      all_apks += split_select.SelectSplits(
+        self, base_apk.path, split_apks, allow_cached_props=allow_cached_props)
+      if len(all_apks) == 1:
+        logging.warning('split-select did not select any from %s', split_apks)
+
+    package_name = base_apk.GetPackageName()
+    device_apk_paths = self._GetApplicationPathsInternal(package_name)
+
+    apks_to_install = None
+    host_checksums = None
+    if not device_apk_paths:
+      apks_to_install = all_apks
+    elif len(device_apk_paths) > 1 and not split_apks:
+      logging.warning(
+          'Installing non-split APK when split APK was previously installed')
+      apks_to_install = all_apks
+    elif len(device_apk_paths) == 1 and split_apks:
+      logging.warning(
+          'Installing split APK when non-split APK was previously installed')
+      apks_to_install = all_apks
+    else:
+      try:
+        apks_to_install, host_checksums = (
+            self._ComputeStaleApks(package_name, all_apks))
+      except EnvironmentError as e:
+        logging.warning('Error calculating md5: %s', e)
+        apks_to_install, host_checksums = all_apks, None
+      if apks_to_install and not reinstall:
+        self.Uninstall(package_name)
+        apks_to_install = all_apks
+
+    if apks_to_install:
+      # Assume that we won't know the resulting device state.
+      self._cache['package_apk_paths'].pop(package_name, 0)
+      self._cache['package_apk_checksums'].pop(package_name, 0)
+      if split_apks:
+        partial = package_name if len(apks_to_install) < len(all_apks) else None
+        self.adb.InstallMultiple(
+            apks_to_install, partial=partial, reinstall=reinstall)
+      else:
+        self.adb.Install(base_apk.path, reinstall=reinstall)
+      if (permissions is None
+          and self.build_version_sdk >= version_codes.MARSHMALLOW):
+        permissions = base_apk.GetPermissions()
+      self.GrantPermissions(package_name, permissions)
+      # Upon success, we know the device checksums, but not their paths.
+      if host_checksums is not None:
+        self._cache['package_apk_checksums'][package_name] = host_checksums
+    else:
+      # Running adb install terminates running instances of the app, so to be
+      # consistent, we explicitly terminate it when skipping the install.
+      self.ForceStop(package_name)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def Uninstall(self, package_name, keep_data=False, timeout=None,
+                retries=None):
+    """Remove the app |package_name| from the device.
+
+    This is a no-op if the app is not already installed.
+
+    Args:
+      package_name: The package to uninstall.
+      keep_data: (optional) Whether to keep the data and cache directories.
+      timeout: Timeout in seconds.
+      retries: Number of retries.
+
+    Raises:
+      CommandFailedError if the uninstallation fails.
+      CommandTimeoutError if the uninstallation times out.
+      DeviceUnreachableError on missing device.
+    """
+    installed = self._GetApplicationPathsInternal(package_name)
+    if not installed:
+      return
+    try:
+      self.adb.Uninstall(package_name, keep_data)
+      self._cache['package_apk_paths'][package_name] = []
+      self._cache['package_apk_checksums'][package_name] = set()
+    except:
+      # Clear cache since we can't be sure of the state.
+      self._cache['package_apk_paths'].pop(package_name, 0)
+      self._cache['package_apk_checksums'].pop(package_name, 0)
+      raise
+
+  def _CheckSdkLevel(self, required_sdk_level):
+    """Raises an exception if the device does not have the required SDK level.
+    """
+    if self.build_version_sdk < required_sdk_level:
+      raise device_errors.DeviceVersionError(
+          ('Requires SDK level %s, device is SDK level %s' %
+           (required_sdk_level, self.build_version_sdk)),
+           device_serial=self.adb.GetDeviceSerial())
+
+
+  @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[:self._MAX_ADB_COMMAND_LENGTH])
+          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.debug('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 = self._Su('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, exact=False, 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.
+      exact: A boolean indicating whether to kill all processes matching
+             the string |process_name| exactly, or all of those which contain
+             |process_name| as a substring. Defaults to False.
+      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.
+    """
+    procs_pids = self.GetPids(process_name)
+    if exact:
+      procs_pids = {process_name: procs_pids.get(process_name, [])}
+    pids = set(itertools.chain(*procs_pids.values()))
+    if not pids:
+      if quiet:
+        return 0
+      else:
+        raise device_errors.CommandFailedError(
+            'No process "%s"' % process_name, str(self))
+
+    logging.info(
+        'KillAll(%r, ...) attempting to kill the following:', process_name)
+    for name, ids  in procs_pids.iteritems():
+      for i in ids:
+        logging.info('  %05s %s', str(i), name)
+
+    cmd = ['kill', '-%d' % signum] + sorted(pids)
+    self.RunShellCommand(cmd, as_root=as_root, check_return=True)
+
+    def all_pids_killed():
+      procs_pids_remain = self.GetPids(process_name)
+      return not pids.intersection(itertools.chain(*procs_pids_remain.values()))
+
+    if blocking:
+      timeout_retry.WaitFor(all_pids_killed, wait_period=0.1)
+
+    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)
+
+    # Store the package name in a shell variable to help the command stay under
+    # the _MAX_ADB_COMMAND_LENGTH limit.
+    package = component.split('/')[0]
+    shell_snippet = 'p=%s;%s' % (package,
+                                 cmd_helper.ShrinkToSnippet(cmd, 'p', package))
+    return self.RunShellCommand(shell_snippet, check_return=True,
+                                large_output=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 and obtain launcher focus.
+
+    This command launches the home screen and attempts to obtain
+    launcher focus until the timeout is reached.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    def is_launcher_focused():
+      output = self.RunShellCommand(['dumpsys', 'window', 'windows'],
+                                    check_return=True, large_output=True)
+      return any(self._LAUNCHER_FOCUSED_RE.match(l) for l in output)
+
+    def dismiss_popups():
+      # There is a dialog present; attempt to get rid of it.
+      # Not all dialogs can be dismissed with back.
+      self.SendKeyEvent(keyevent.KEYCODE_ENTER)
+      self.SendKeyEvent(keyevent.KEYCODE_BACK)
+      return is_launcher_focused()
+
+    # If Home is already focused, return early to avoid unnecessary work.
+    if is_launcher_focused():
+      return
+
+    self.StartActivity(
+        intent.Intent(action='android.intent.action.MAIN',
+                      category='android.intent.category.HOME'),
+        blocking=True)
+
+    if not is_launcher_focused():
+      timeout_retry.WaitFor(dismiss_popups, wait_period=1)
+
+  @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.
+    """
+    cmd = 'p=%s;if [[ "$(ps)" = *$p* ]]; then am force-stop $p; fi'
+    self.RunShellCommand(cmd % package, check_return=True)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def ClearApplicationState(
+      self, package, permissions=None, timeout=None, retries=None):
+    """Clear all state for the given package.
+
+    Args:
+      package: A string containing the name of the package to stop.
+      permissions: List of permissions to set after clearing data.
+      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 >= version_codes.JELLY_BEAN_MR2)
+        or self._GetApplicationPathsInternal(package)):
+      self.RunShellCommand(['pm', 'clear', package], check_return=True)
+      self.GrantPermissions(package, permissions)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def SendKeyEvent(self, keycode, timeout=None, retries=None):
+    """Sends a keycode to the device.
+
+    See the devil.android.sdk.keyevent module for suitable keycode values.
+
+    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
+
+  @decorators.WithTimeoutAndRetriesFromInstance(
+      min_default_timeout=PUSH_CHANGED_FILES_DEFAULT_TIMEOUT)
+  def PushChangedFiles(self, host_device_tuples, timeout=None,
+                       retries=None, delete_device_stale=False):
+    """Push files to the device, skipping files that don't need updating.
+
+    When a directory is pushed, it is traversed recursively on the host and
+    all files in it are pushed to the device as needed.
+    Additionally, if delete_device_stale option is True,
+    files that exist on the device but don't exist on the host are deleted.
+
+    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
+      delete_device_stale: option to delete stale files on device
+
+    Raises:
+      CommandFailedError on failure.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+
+    all_changed_files = []
+    all_stale_files = []
+    missing_dirs = []
+    cache_commit_funcs = []
+    for h, d in host_device_tuples:
+      changed_files, up_to_date_files, stale_files, cache_commit_func = (
+          self._GetChangedAndStaleFiles(h, d, delete_device_stale))
+      all_changed_files += changed_files
+      all_stale_files += stale_files
+      cache_commit_funcs.append(cache_commit_func)
+      if (os.path.isdir(h) and changed_files and not up_to_date_files
+          and not stale_files):
+        missing_dirs.append(d)
+
+    if delete_device_stale and all_stale_files:
+      self.RunShellCommand(['rm', '-f'] + all_stale_files,
+                             check_return=True)
+
+    if all_changed_files:
+      if missing_dirs:
+        self.RunShellCommand(['mkdir', '-p'] + missing_dirs, check_return=True)
+      self._PushFilesImpl(host_device_tuples, all_changed_files)
+    for func in cache_commit_funcs:
+      func()
+
+  def _GetChangedAndStaleFiles(self, host_path, device_path, track_stale=False):
+    """Get files to push and delete
+
+    Args:
+      host_path: an absolute path of a file or directory on the host
+      device_path: an absolute path of a file or directory on the device
+      track_stale: whether to bother looking for stale files (slower)
+
+    Returns:
+      a three-element tuple
+      1st element: a list of (host_files_path, device_files_path) tuples to push
+      2nd element: a list of host_files_path that are up-to-date
+      3rd element: a list of stale files under device_path, or [] when
+        track_stale == False
+    """
+    try:
+      # Length calculations below assume no trailing /.
+      host_path = host_path.rstrip('/')
+      device_path = device_path.rstrip('/')
+
+      specific_device_paths = [device_path]
+      ignore_other_files = not track_stale and os.path.isdir(host_path)
+      if ignore_other_files:
+        specific_device_paths = []
+        for root, _, filenames in os.walk(host_path):
+          relative_dir = root[len(host_path) + 1:]
+          specific_device_paths.extend(
+              posixpath.join(device_path, relative_dir, f) for f in filenames)
+
+      def calculate_host_checksums():
+        return md5sum.CalculateHostMd5Sums([host_path])
+
+      def calculate_device_checksums():
+        if self._enable_device_files_cache:
+          cache_entry = self._cache['device_path_checksums'].get(device_path)
+          if cache_entry and cache_entry[0] == ignore_other_files:
+            return dict(cache_entry[1])
+
+        sums = md5sum.CalculateDeviceMd5Sums(specific_device_paths, self)
+
+        cache_entry = [ignore_other_files, sums]
+        self._cache['device_path_checksums'][device_path] = cache_entry
+        return dict(sums)
+
+      host_checksums, device_checksums = reraiser_thread.RunAsync((
+          calculate_host_checksums,
+          calculate_device_checksums))
+    except EnvironmentError as e:
+      logging.warning('Error calculating md5: %s', e)
+      return ([(host_path, device_path)], [], [], lambda: 0)
+
+    to_push = []
+    up_to_date = []
+    to_delete = []
+    if os.path.isfile(host_path):
+      host_checksum = host_checksums.get(host_path)
+      device_checksum = device_checksums.get(device_path)
+      if host_checksum == device_checksum:
+        up_to_date.append(host_path)
+      else:
+        to_push.append((host_path, device_path))
+    else:
+      for host_abs_path, host_checksum in host_checksums.iteritems():
+        device_abs_path = posixpath.join(
+            device_path, os.path.relpath(host_abs_path, host_path))
+        device_checksum = device_checksums.pop(device_abs_path, None)
+        if device_checksum == host_checksum:
+          up_to_date.append(host_abs_path)
+        else:
+          to_push.append((host_abs_path, device_abs_path))
+      to_delete = device_checksums.keys()
+
+    def cache_commit_func():
+      new_sums = {posixpath.join(device_path, path[len(host_path) + 1:]): val
+                  for path, val in host_checksums.iteritems()}
+      cache_entry = [ignore_other_files, new_sums]
+      self._cache['device_path_checksums'][device_path] = cache_entry
+
+    return (to_push, up_to_date, to_delete, cache_commit_func)
+
+  def _ComputeDeviceChecksumsForApks(self, package_name):
+    ret = self._cache['package_apk_checksums'].get(package_name)
+    if ret is None:
+      device_paths = self._GetApplicationPathsInternal(package_name)
+      file_to_checksums = md5sum.CalculateDeviceMd5Sums(device_paths, self)
+      ret = set(file_to_checksums.values())
+      self._cache['package_apk_checksums'][package_name] = ret
+    return ret
+
+  def _ComputeStaleApks(self, package_name, host_apk_paths):
+    def calculate_host_checksums():
+      return md5sum.CalculateHostMd5Sums(host_apk_paths)
+
+    def calculate_device_checksums():
+      return self._ComputeDeviceChecksumsForApks(package_name)
+
+    host_checksums, device_checksums = reraiser_thread.RunAsync((
+        calculate_host_checksums, calculate_device_checksums))
+    stale_apks = [k for (k, v) in host_checksums.iteritems()
+                  if v not in device_checksums]
+    return stale_apks, set(host_checksums.values())
+
+  def _PushFilesImpl(self, host_device_tuples, files):
+    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)
+
+    if dir_push_duration < push_duration and dir_push_duration < zip_duration:
+      self._PushChangedFilesIndividually(host_device_tuples)
+    elif push_duration < zip_duration:
+      self._PushChangedFilesIndividually(files)
+    elif self._commands_installed is False:
+      # Already tried and failed to install unzip command.
+      self._PushChangedFilesIndividually(files)
+    elif not self._PushChangedFilesZipped(
+        files, [d for _, d in host_device_tuples]):
+      self._PushChangedFilesIndividually(files)
+
+  def _MaybeInstallCommands(self):
+    if self._commands_installed is None:
+      try:
+        if not install_commands.Installed(self):
+          install_commands.InstallCommands(self)
+        self._commands_installed = True
+      except device_errors.CommandFailedError as e:
+        logging.warning('unzip not available: %s', str(e))
+        self._commands_installed = False
+    return self._commands_installed
+
+  @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, dirs):
+    with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file:
+      zip_proc = multiprocessing.Process(
+          target=DeviceUtils._CreateDeviceZip,
+          args=(zip_file.name, files))
+      zip_proc.start()
+      try:
+        # While it's zipping, ensure the unzip command exists on the device.
+        if not self._MaybeInstallCommands():
+          zip_proc.terminate()
+          return False
+
+        # Warm up NeedsSU cache while we're still zipping.
+        self.NeedsSU()
+        with device_temp_file.DeviceTempFile(
+            self.adb, suffix='.zip') as device_temp:
+          zip_proc.join()
+          self.adb.Push(zip_file.name, device_temp.name)
+          quoted_dirs = ' '.join(cmd_helper.SingleQuote(d) for d in dirs)
+          self.RunShellCommand(
+              'unzip %s&&chmod -R 777 %s' % (device_temp.name, quoted_dirs),
+              as_root=True,
+              env={'PATH': '%s:$PATH' % install_commands.BIN_DIR},
+              check_return=True)
+      finally:
+        if zip_proc.is_alive():
+          zip_proc.terminate()
+    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)
+
+  # TODO(nednguyen): remove this and migrate the callsite to PathExists().
+  def FileExists(self, device_path, timeout=None, retries=None):
+    """Checks whether the given file exists on the device.
+
+    Arguments are the same as PathExists.
+    """
+    return self.PathExists(device_path, timeout=timeout, retries=retries)
+
+  def PathExists(self, device_paths, timeout=None, retries=None):
+    """Checks whether the given path(s) exists on the device.
+
+    Args:
+      device_path: A string containing the absolute path to the file on the
+                   device, or an iterable of paths to check.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      True if the all given paths exist on the device, False otherwise.
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    paths = device_paths
+    if isinstance(paths, basestring):
+      paths = (paths,)
+    condition = ' -a '.join('-e %s' % cmd_helper.SingleQuote(p) for p in paths)
+    cmd = 'test %s;echo $?' % condition
+    result = self.RunShellCommand(cmd, check_return=True, timeout=timeout,
+                                  retries=retries)
+    return '0' == result[0]
+
+  @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:
+        cmd = 'SRC=%s DEST=%s;cp "$SRC" "$DEST" && chmod 666 "$DEST"' % (
+            cmd_helper.SingleQuote(device_path),
+            cmd_helper.SingleQuote(device_temp.name))
+        self.RunShellCommand(cmd, 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(self.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(self.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
+
+  def GetLanguage(self, cache=False):
+    """Returns the language setting on the device.
+    Args:
+      cache: Whether to use cached properties when available.
+    """
+    return self.GetProp('persist.sys.language', cache=cache)
+
+  def GetCountry(self, cache=False):
+    """Returns the country setting on the device.
+
+    Args:
+      cache: Whether to use cached properties when available.
+    """
+    return self.GetProp('persist.sys.country', cache=cache)
+
+
+  @property
+  def screen_density(self):
+    """Returns the screen density of the device."""
+    DPI_TO_DENSITY = {
+      120: 'ldpi',
+      160: 'mdpi',
+      240: 'hdpi',
+      320: 'xhdpi',
+      480: 'xxhdpi',
+      640: 'xxxhdpi',
+    }
+    dpi = int(self.GetProp('ro.sf.lcd_density', cache=True))
+    return DPI_TO_DENSITY.get(dpi, 'tvdpi')
+
+  @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 devil.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)
+
+  @property
+  def product_board(self):
+    """Returns the product board name of the device (e.g. 'shamu')."""
+    return self.GetProp('ro.product.board', 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: Whether to use cached properties when available.
+      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)
+
+    prop_cache = self._cache['getprop']
+    if cache:
+      if property_name not in prop_cache:
+        # It takes ~120ms to query a single property, and ~130ms to query all
+        # properties. So, when caching we always query all properties.
+        output = self.RunShellCommand(
+            ['getprop'], check_return=True, large_output=True,
+            timeout=self._default_timeout if timeout is DEFAULT else timeout,
+            retries=self._default_retries if retries is DEFAULT else retries)
+        prop_cache.clear()
+        for key, value in _GETPROP_RE.findall(''.join(output)):
+          prop_cache[key] = value
+        if property_name not in prop_cache:
+          prop_cache[property_name] = ''
+    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)
+      prop_cache[property_name] = value
+    return prop_cache[property_name]
+
+  @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)
+    prop_cache = self._cache['getprop']
+    if property_name in prop_cache:
+      del prop_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, cache=False):
+      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', cache=True)
+
+  @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 a list of PIDs for each process that
+      contained the provided |process_name|.
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    procs_pids = collections.defaultdict(list)
+    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]:
+          pid, process = ps_data[1], ps_data[-1]
+          procs_pids[process].append(pid)
+      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
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def DismissCrashDialogIfNeeded(self, timeout=None, retries=None):
+    """Dismiss the error/ANR dialog if present.
+
+    Returns: Name of the crashed package if a dialog is focused,
+             None otherwise.
+    """
+    def _FindFocusedWindow():
+      match = None
+      # 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 line in self.RunShellCommand(['dumpsys', 'window', 'windows'],
+                                       check_return=True, large_output=True):
+        match = re.match(_CURRENT_FOCUS_CRASH_RE, line)
+        if match:
+          break
+      return match
+
+    match = _FindFocusedWindow()
+    if not match:
+      return None
+    package = match.group(2)
+    logging.warning('Trying to dismiss %s dialog for %s', *match.groups())
+    self.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT)
+    self.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT)
+    self.SendKeyEvent(keyevent.KEYCODE_ENTER)
+    match = _FindFocusedWindow()
+    if match:
+      logging.error('Still showing a %s dialog for %s', *match.groups())
+    return package
+
+  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])}
+    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)
+
+  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 = {
+        # Map of packageId -> list of on-device .apk paths
+        'package_apk_paths': {},
+        # Set of packageId that were loaded from LoadCacheData and not yet
+        # verified.
+        'package_apk_paths_to_verify': set(),
+        # Map of packageId -> set of on-device .apk checksums
+        'package_apk_checksums': {},
+        # Map of property_name -> value
+        'getprop': {},
+        # Map of device_path -> [ignore_other_files, map of path->checksum]
+        'device_path_checksums': {},
+    }
+
+  def LoadCacheData(self, data):
+    """Initializes the cache from data created using DumpCacheData."""
+    obj = json.loads(data)
+    self._cache['package_apk_paths'] = obj.get('package_apk_paths', {})
+    # When using a cache across script invokations, verify that apps have
+    # not been uninstalled.
+    self._cache['package_apk_paths_to_verify'] = set(
+        self._cache['package_apk_paths'].iterkeys())
+
+    package_apk_checksums = obj.get('package_apk_checksums', {})
+    for k, v in package_apk_checksums.iteritems():
+      package_apk_checksums[k] = set(v)
+    self._cache['package_apk_checksums'] = package_apk_checksums
+    device_path_checksums = obj.get('device_path_checksums', {})
+    self._cache['device_path_checksums'] = device_path_checksums
+
+  def DumpCacheData(self):
+    """Dumps the current cache state to a string."""
+    obj = {}
+    obj['package_apk_paths'] = self._cache['package_apk_paths']
+    obj['package_apk_checksums'] = self._cache['package_apk_checksums']
+    # JSON can't handle sets.
+    for k, v in obj['package_apk_checksums'].iteritems():
+      obj['package_apk_checksums'][k] = list(v)
+    obj['device_path_checksums'] = self._cache['device_path_checksums']
+    return json.dumps(obj, separators=(',', ':'))
+
+  @classmethod
+  def parallel(cls, devices, async=False):
+    """Creates a Parallelizer to operate over the provided list of devices.
+
+    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|.
+
+    Raises:
+      device_errors.NoDevicesError: If no devices are passed.
+    """
+    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=None, **kwargs):
+    blacklisted_devices = blacklist.Read() if blacklist else []
+    def blacklisted(adb):
+      if adb.GetDeviceSerial() in blacklisted_devices:
+        logging.warning('Device %s is blacklisted.', adb.GetDeviceSerial())
+        return True
+      return False
+
+    return [cls(adb, **kwargs) for adb in adb_wrapper.AdbWrapper.Devices()
+            if not blacklisted(adb)]
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def RestartAdbd(self, timeout=None, retries=None):
+    logging.info('Restarting adbd on device.')
+    with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script:
+      self.WriteFile(script.name, _RESTART_ADBD_SCRIPT)
+      self.RunShellCommand(['source', script.name], as_root=True)
+      self.adb.WaitForDevice()
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GrantPermissions(self, package, permissions, timeout=None, retries=None):
+    # Permissions only need to be set on M and above because of the changes to
+    # the permission model.
+    if not permissions or self.build_version_sdk < version_codes.MARSHMALLOW:
+      return
+    # TODO(rnephew): After permission blacklist is complete, switch to using
+    # &&s instead of ;s.
+    cmd = ''
+    logging.info('Setting permissions for %s.', package)
+    permissions = [p for p in permissions if p not in _PERMISSIONS_BLACKLIST]
+    if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions
+        and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions):
+      permissions.append('android.permission.READ_EXTERNAL_STORAGE')
+    cmd = ';'.join('pm grant %s %s' %(package, p) for p in permissions)
+    if cmd:
+      output = self.RunShellCommand(cmd)
+      if output:
+        logging.warning('Possible problem when granting permissions. Blacklist '
+                        'may need to be updated.')
+        logging.warning(output)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def IsScreenOn(self, timeout=None, retries=None):
+    """Determines if screen is on.
+
+    Dumpsys input_method exposes screen on/off state. Below is an explination of
+    the states.
+
+    Pre-L:
+      On: mScreenOn=true
+      Off: mScreenOn=false
+    L+:
+      On: mInteractive=true
+      Off: mInteractive=false
+
+    Returns:
+      True if screen is on, false if it is off.
+
+    Raises:
+      device_errors.CommandFailedError: If screen state cannot be found.
+    """
+    if self.build_version_sdk < version_codes.LOLLIPOP:
+       input_check = 'mScreenOn'
+       check_value = 'mScreenOn=true'
+    else:
+       input_check = 'mInteractive'
+       check_value = 'mInteractive=true'
+    dumpsys_out = self._RunPipedShellCommand(
+        'dumpsys input_method | grep %s' % input_check)
+    if not dumpsys_out:
+      raise device_errors.CommandFailedError(
+          'Unable to detect screen state', str(self))
+    return check_value in dumpsys_out[0]
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def SetScreen(self, on, timeout=None, retries=None):
+    """Turns screen on and off.
+
+    Args:
+      on: bool to decide state to switch to. True = on False = off.
+    """
+    def screen_test():
+      return self.IsScreenOn() == on
+
+    if screen_test():
+      logging.info('Screen already in expected state.')
+      return
+    self.RunShellCommand('input keyevent 26')
+    timeout_retry.WaitFor(screen_test, wait_period=1)
diff --git a/build/android/devil/android/device_utils_device_test.py b/build/android/devil/android/device_utils_device_test.py
new file mode 100755
index 0000000..4334a0f
--- /dev/null
+++ b/build/android/devil/android/device_utils_device_test.py
@@ -0,0 +1,219 @@
+#!/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 device_utils.py (mostly DeviceUtils).
+The test will invoke real devices
+"""
+
+import os
+import tempfile
+import unittest
+
+from pylib import constants
+from devil.android import device_utils
+from devil.android.sdk import adb_wrapper
+from devil.utils import cmd_helper
+
+_OLD_CONTENTS = "foo"
+_NEW_CONTENTS = "bar"
+_DEVICE_DIR = "/data/local/tmp/device_utils_test"
+_SUB_DIR = "sub"
+_SUB_DIR1 = "sub1"
+_SUB_DIR2 = "sub2"
+
+class DeviceUtilsPushDeleteFilesTest(unittest.TestCase):
+
+  def setUp(self):
+    devices = adb_wrapper.AdbWrapper.Devices()
+    assert devices, 'A device must be attached'
+    self.adb = devices[0]
+    self.adb.WaitForDevice()
+    self.device = device_utils.DeviceUtils(
+        self.adb, default_timeout=10, default_retries=0)
+    default_build_type = os.environ.get('BUILDTYPE', 'Debug')
+    constants.SetBuildType(default_build_type)
+
+  @staticmethod
+  def _MakeTempFile(contents):
+    """Make a temporary file with the given contents.
+
+    Args:
+      contents: string to write to the temporary file.
+
+    Returns:
+      the tuple contains the absolute path to the file and the file name
+    """
+    fi, path = tempfile.mkstemp(text=True)
+    with os.fdopen(fi, 'w') as f:
+      f.write(contents)
+    file_name = os.path.basename(path)
+    return (path, file_name)
+
+  @staticmethod
+  def _MakeTempFileGivenDir(directory, contents):
+    """Make a temporary file under the given directory
+    with the given contents
+
+    Args:
+      directory: the temp directory to create the file
+      contents: string to write to the temp file
+
+    Returns:
+      the list contains the absolute path to the file and the file name
+    """
+    fi, path = tempfile.mkstemp(dir=directory, text=True)
+    with os.fdopen(fi, 'w') as f:
+      f.write(contents)
+    file_name = os.path.basename(path)
+    return (path, file_name)
+
+  @staticmethod
+  def _ChangeTempFile(path, contents):
+    with os.open(path, 'w') as f:
+      f.write(contents)
+
+  @staticmethod
+  def _DeleteTempFile(path):
+    os.remove(path)
+
+  def testPushChangedFiles_noFileChange(self):
+    (host_file_path, file_name) = self._MakeTempFile(_OLD_CONTENTS)
+    device_file_path = "%s/%s" % (_DEVICE_DIR, file_name)
+    self.adb.Push(host_file_path, device_file_path)
+    self.device.PushChangedFiles([(host_file_path, device_file_path)])
+    result = self.device.RunShellCommand(['cat', device_file_path],
+                                         single_line=True)
+    self.assertEqual(_OLD_CONTENTS, result)
+
+    cmd_helper.RunCmd(['rm', host_file_path])
+    self.device.RunShellCommand(['rm', '-rf', _DEVICE_DIR])
+
+  def testPushChangedFiles_singleFileChange(self):
+    (host_file_path, file_name) = self._MakeTempFile(_OLD_CONTENTS)
+    device_file_path = "%s/%s" % (_DEVICE_DIR, file_name)
+    self.adb.Push(host_file_path, device_file_path)
+
+    with open(host_file_path, 'w') as f:
+      f.write(_NEW_CONTENTS)
+    self.device.PushChangedFiles([(host_file_path, device_file_path)])
+    result = self.device.RunShellCommand(['cat', device_file_path],
+                                         single_line=True)
+    self.assertEqual(_NEW_CONTENTS, result)
+
+    cmd_helper.RunCmd(['rm', host_file_path])
+    self.device.RunShellCommand(['rm', '-rf', _DEVICE_DIR])
+
+  def testDeleteFiles(self):
+    host_tmp_dir = tempfile.mkdtemp()
+    (host_file_path, file_name) = self._MakeTempFileGivenDir(
+        host_tmp_dir, _OLD_CONTENTS)
+
+    device_file_path = "%s/%s" % (_DEVICE_DIR, file_name)
+    self.adb.Push(host_file_path, device_file_path)
+
+    cmd_helper.RunCmd(['rm', host_file_path])
+    self.device.PushChangedFiles([(host_tmp_dir, _DEVICE_DIR)],
+                                 delete_device_stale=True)
+    result = self.device.RunShellCommand(['ls', _DEVICE_DIR], single_line=True)
+    self.assertEqual('', result)
+
+    cmd_helper.RunCmd(['rm', '-rf', host_tmp_dir])
+    self.device.RunShellCommand(['rm', '-rf', _DEVICE_DIR])
+
+  def testPushAndDeleteFiles_noSubDir(self):
+    host_tmp_dir = tempfile.mkdtemp()
+    (host_file_path1, file_name1) = self._MakeTempFileGivenDir(
+        host_tmp_dir, _OLD_CONTENTS)
+    (host_file_path2, file_name2) = self._MakeTempFileGivenDir(
+        host_tmp_dir, _OLD_CONTENTS)
+
+    device_file_path1 = "%s/%s" % (_DEVICE_DIR, file_name1)
+    device_file_path2 = "%s/%s" % (_DEVICE_DIR, file_name2)
+    self.adb.Push(host_file_path1, device_file_path1)
+    self.adb.Push(host_file_path2, device_file_path2)
+
+    with open(host_file_path1, 'w') as f:
+      f.write(_NEW_CONTENTS)
+    cmd_helper.RunCmd(['rm', host_file_path2])
+
+    self.device.PushChangedFiles([(host_tmp_dir, _DEVICE_DIR)],
+                                   delete_device_stale=True)
+    result = self.device.RunShellCommand(['cat', device_file_path1],
+                                         single_line=True)
+    self.assertEqual(_NEW_CONTENTS, result)
+    result = self.device.RunShellCommand(['ls', _DEVICE_DIR], single_line=True)
+    self.assertEqual(file_name1, result)
+
+    self.device.RunShellCommand(['rm', '-rf', _DEVICE_DIR])
+    cmd_helper.RunCmd(['rm', '-rf', host_tmp_dir])
+
+  def testPushAndDeleteFiles_SubDir(self):
+    host_tmp_dir = tempfile.mkdtemp()
+    host_sub_dir1 = "%s/%s" % (host_tmp_dir, _SUB_DIR1)
+    host_sub_dir2 = "%s/%s/%s" % (host_tmp_dir, _SUB_DIR, _SUB_DIR2)
+    cmd_helper.RunCmd(['mkdir', '-p', host_sub_dir1])
+    cmd_helper.RunCmd(['mkdir', '-p', host_sub_dir2])
+
+    (host_file_path1, file_name1) = self._MakeTempFileGivenDir(
+        host_tmp_dir, _OLD_CONTENTS)
+    (host_file_path2, file_name2) = self._MakeTempFileGivenDir(
+        host_tmp_dir, _OLD_CONTENTS)
+    (host_file_path3, file_name3) = self._MakeTempFileGivenDir(
+        host_sub_dir1, _OLD_CONTENTS)
+    (host_file_path4, file_name4) = self._MakeTempFileGivenDir(
+        host_sub_dir2, _OLD_CONTENTS)
+
+    device_file_path1 = "%s/%s" % (_DEVICE_DIR, file_name1)
+    device_file_path2 = "%s/%s" % (_DEVICE_DIR, file_name2)
+    device_file_path3 = "%s/%s/%s" % (_DEVICE_DIR, _SUB_DIR1, file_name3)
+    device_file_path4 = "%s/%s/%s/%s" % (_DEVICE_DIR, _SUB_DIR,
+                                         _SUB_DIR2, file_name4)
+
+    self.adb.Push(host_file_path1, device_file_path1)
+    self.adb.Push(host_file_path2, device_file_path2)
+    self.adb.Push(host_file_path3, device_file_path3)
+    self.adb.Push(host_file_path4, device_file_path4)
+
+    with open(host_file_path1, 'w') as f:
+      f.write(_NEW_CONTENTS)
+    cmd_helper.RunCmd(['rm', host_file_path2])
+    cmd_helper.RunCmd(['rm', host_file_path4])
+
+    self.device.PushChangedFiles([(host_tmp_dir, _DEVICE_DIR)],
+                                   delete_device_stale=True)
+    result = self.device.RunShellCommand(['cat', device_file_path1],
+                                         single_line=True)
+    self.assertEqual(_NEW_CONTENTS, result)
+
+    result = self.device.RunShellCommand(['ls', _DEVICE_DIR])
+    self.assertIn(file_name1, result)
+    self.assertIn(_SUB_DIR1, result)
+    self.assertIn(_SUB_DIR, result)
+    self.assertEqual(3, len(result))
+
+    result = self.device.RunShellCommand(['cat', device_file_path3],
+                                      single_line=True)
+    self.assertEqual(_OLD_CONTENTS, result)
+
+    result = self.device.RunShellCommand(["ls", "%s/%s/%s"
+                                          % (_DEVICE_DIR, _SUB_DIR, _SUB_DIR2)],
+                                         single_line=True)
+    self.assertEqual('', result)
+
+    self.device.RunShellCommand(['rm', '-rf', _DEVICE_DIR])
+    cmd_helper.RunCmd(['rm', '-rf', host_tmp_dir])
+
+  def testRestartAdbd(self):
+    old_adbd_pid = self.device.RunShellCommand(
+        ['ps', '|', 'grep', 'adbd'])[1].split()[1]
+    self.device.RestartAdbd()
+    new_adbd_pid = self.device.RunShellCommand(
+        ['ps', '|', 'grep', 'adbd'])[1].split()[1]
+    self.assertNotEqual(old_adbd_pid, new_adbd_pid)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/devil/android/device_utils_test.py b/build/android/devil/android/device_utils_test.py
new file mode 100755
index 0000000..09c527e
--- /dev/null
+++ b/build/android/devil/android/device_utils_test.py
@@ -0,0 +1,2224 @@
+#!/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=protected-access
+# pylint: disable=unused-argument
+
+import logging
+import os
+import sys
+import unittest
+
+from devil.android import device_errors
+from devil.android import device_signal
+from devil.android import device_utils
+from devil.android.sdk import adb_wrapper
+from devil.android.sdk import intent
+from devil.android.sdk import version_codes
+from devil.utils import cmd_helper
+from devil.utils import mock_calls
+from pylib import constants
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class _MockApkHelper(object):
+  def __init__(self, path, package_name, perms=None):
+    self.path = path
+    self.package_name = package_name
+    self.perms = perms
+
+  def GetPackageName(self):
+    return self.package_name
+
+  def GetPermissions(self):
+    return self.perms
+
+
+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 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.devil.utils.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.devil.android.sdk.adb_wrapper.AdbWrapper.KillServer(),
+        (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
+            ['pgrep', 'adb']),
+         (1, '')),
+        mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.StartServer(),
+        (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
+            ['pgrep', 'adb']),
+         (1, '')),
+        (mock.call.devil.utils.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, is_ready=True):
+  adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
+  adb.__str__ = mock.Mock(return_value=test_serial)
+  adb.GetDeviceSerial.return_value = test_serial
+  adb.is_ready = is_ready
+  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 AdbCommandError(self, args=None, output=None, status=None, msg=None):
+    if args is None:
+      args = ['[unspecified]']
+    return mock.Mock(side_effect=device_errors.AdbCommandFailedError(
+        args, output, status, 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)))
+
+  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)))
+
+
+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.device.WaitUntilFullyBooted()):
+      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 DeviceUtilsGetApplicationPathsInternalTest(DeviceUtilsTest):
+
+  def testGetApplicationPathsInternal_exists(self):
+    with self.assertCalls(
+        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
+        (self.call.device.RunShellCommand(
+            ['pm', 'path', 'android'], check_return=True),
+         ['package:/path/to/android.apk'])):
+      self.assertEquals(['/path/to/android.apk'],
+                        self.device._GetApplicationPathsInternal('android'))
+
+  def testGetApplicationPathsInternal_notExists(self):
+    with self.assertCalls(
+        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
+        (self.call.device.RunShellCommand(
+            ['pm', 'path', 'not.installed.app'], check_return=True),
+         '')):
+      self.assertEquals([],
+          self.device._GetApplicationPathsInternal('not.installed.app'))
+
+  def testGetApplicationPathsInternal_fails(self):
+    with self.assertCalls(
+        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
+        (self.call.device.RunShellCommand(
+            ['pm', 'path', 'android'], check_return=True),
+         self.CommandError('ERROR. Is package manager running?\n'))):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device._GetApplicationPathsInternal('android')
+
+
+class DeviceUtils_GetApplicationVersionTest(DeviceUtilsTest):
+
+  def test_GetApplicationVersion_exists(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('dumpsys package com.android.chrome'),
+         'Packages:\n'
+         '  Package [com.android.chrome] (3901ecfb):\n'
+         '    userId=1234 gids=[123, 456, 789]\n'
+         '    pkg=Package{1fecf634 com.android.chrome}\n'
+         '    versionName=45.0.1234.7\n')):
+      self.assertEquals('45.0.1234.7',
+                        self.device.GetApplicationVersion('com.android.chrome'))
+
+  def test_GetApplicationVersion_notExists(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('dumpsys package com.android.chrome'), '')):
+      self.assertEquals(None,
+                        self.device.GetApplicationVersion('com.android.chrome'))
+
+  def test_GetApplicationVersion_fails(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('dumpsys package com.android.chrome'),
+         'Packages:\n'
+         '  Package [com.android.chrome] (3901ecfb):\n'
+         '    userId=1234 gids=[123, 456, 789]\n'
+         '    pkg=Package{1fecf634 com.android.chrome}\n')):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.GetApplicationVersion('com.android.chrome')
+
+
+class DeviceUtilsGetApplicationDataDirectoryTest(DeviceUtilsTest):
+
+  def testGetApplicationDataDirectory_exists(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand(
+            'pm dump foo.bar.baz | grep dataDir='),
+        ['dataDir=/data/data/foo.bar.baz']):
+      self.assertEquals(
+          '/data/data/foo.bar.baz',
+          self.device.GetApplicationDataDirectory('foo.bar.baz'))
+
+  def testGetApplicationDataDirectory_notExists(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand(
+            'pm dump foo.bar.baz | grep dataDir='),
+        self.ShellError()):
+      self.assertIsNone(self.device.GetApplicationDataDirectory('foo.bar.baz'))
+
+
+@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._GetApplicationPathsInternal('android',
+                                                       skip_cache=True),
+         ['package:/some/fake/path']),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed', cache=False), '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._GetApplicationPathsInternal('android',
+                                                       skip_cache=True),
+         ['package:/some/fake/path']),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
+        # wifi_enabled
+        (self.call.adb.Shell('dumpsys wifi'),
+         'stuff\nWi-Fi is enabled\nmore stuff\n')):
+      self.device.WaitUntilFullyBooted(wifi=True)
+
+  def testWaitUntilFullyBooted_deviceNotInitiallyAvailable(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device._GetApplicationPathsInternal('android',
+                                                       skip_cache=True),
+         ['package:/some/fake/path']),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
+      self.device.WaitUntilFullyBooted(wifi=False)
+
+  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._GetApplicationPathsInternal('android',
+                                                       skip_cache=True),
+         self.CommandError()),
+        # pm_ready
+        (self.call.device._GetApplicationPathsInternal('android',
+                                                       skip_cache=True),
+         self.CommandError()),
+        # pm_ready
+        (self.call.device._GetApplicationPathsInternal('android',
+                                                       skip_cache=True),
+         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._GetApplicationPathsInternal('android',
+                                                       skip_cache=True),
+         ['package:/some/fake/path']),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed', cache=False), '0'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed', cache=False), '0'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed', cache=False),
+         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._GetApplicationPathsInternal('android',
+                                                       skip_cache=True),
+         ['package:/some/fake/path']),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed', cache=False), '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):
+
+  mock_apk = _MockApkHelper('/fake/test/app.apk', 'test.package', ['p1'])
+
+  def testInstall_noPriorInstall(self):
+    with self.patch_call(self.call.device.build_version_sdk, return_value=23):
+      with self.assertCalls(
+          (self.call.device._GetApplicationPathsInternal('test.package'), []),
+          self.call.adb.Install('/fake/test/app.apk', reinstall=False),
+          (self.call.device.GrantPermissions('test.package', ['p1']), [])):
+        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
+
+  def testInstall_permissionsPreM(self):
+    with self.patch_call(self.call.device.build_version_sdk, return_value=20):
+      with self.assertCalls(
+          (self.call.device._GetApplicationPathsInternal('test.package'), []),
+          (self.call.adb.Install('/fake/test/app.apk', reinstall=False))):
+        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
+
+  def testInstall_findPermissions(self):
+    with self.patch_call(self.call.device.build_version_sdk, return_value=23):
+      with self.assertCalls(
+          (self.call.device._GetApplicationPathsInternal('test.package'), []),
+          (self.call.adb.Install('/fake/test/app.apk', reinstall=False)),
+          (self.call.device.GrantPermissions('test.package', ['p1']), [])):
+        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
+
+  def testInstall_passPermissions(self):
+    with self.assertCalls(
+        (self.call.device._GetApplicationPathsInternal('test.package'), []),
+        (self.call.adb.Install('/fake/test/app.apk', reinstall=False)),
+        (self.call.device.GrantPermissions('test.package', ['p1', 'p2']), [])):
+      self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0,
+                          permissions=['p1', 'p2'])
+
+  def testInstall_differentPriorInstall(self):
+    with self.assertCalls(
+        (self.call.device._GetApplicationPathsInternal('test.package'),
+         ['/fake/data/app/test.package.apk']),
+        (self.call.device._ComputeStaleApks('test.package',
+            ['/fake/test/app.apk']),
+         (['/fake/test/app.apk'], None)),
+        self.call.device.Uninstall('test.package'),
+        self.call.adb.Install('/fake/test/app.apk', reinstall=False)):
+      self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0,
+                          permissions=[])
+
+  def testInstall_differentPriorInstall_reinstall(self):
+    with self.assertCalls(
+        (self.call.device._GetApplicationPathsInternal('test.package'),
+         ['/fake/data/app/test.package.apk']),
+        (self.call.device._ComputeStaleApks('test.package',
+            ['/fake/test/app.apk']),
+         (['/fake/test/app.apk'], None)),
+        self.call.adb.Install('/fake/test/app.apk', reinstall=True)):
+      self.device.Install(DeviceUtilsInstallTest.mock_apk,
+          reinstall=True, retries=0, permissions=[])
+
+  def testInstall_identicalPriorInstall_reinstall(self):
+    with self.assertCalls(
+        (self.call.device._GetApplicationPathsInternal('test.package'),
+         ['/fake/data/app/test.package.apk']),
+        (self.call.device._ComputeStaleApks('test.package',
+            ['/fake/test/app.apk']),
+         ([], None)),
+        (self.call.device.ForceStop('test.package'))):
+      self.device.Install(DeviceUtilsInstallTest.mock_apk,
+          reinstall=True, retries=0, permissions=[])
+
+  def testInstall_fails(self):
+    with self.assertCalls(
+        (self.call.device._GetApplicationPathsInternal('test.package'), []),
+        (self.call.adb.Install('/fake/test/app.apk', reinstall=False),
+         self.CommandError('Failure\r\n'))):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
+
+class DeviceUtilsInstallSplitApkTest(DeviceUtilsTest):
+
+  mock_apk = _MockApkHelper('base.apk', 'test.package', ['p1'])
+
+  def testInstallSplitApk_noPriorInstall(self):
+    with self.assertCalls(
+        (self.call.device._CheckSdkLevel(21)),
+        (mock.call.devil.android.sdk.split_select.SelectSplits(
+            self.device, 'base.apk',
+            ['split1.apk', 'split2.apk', 'split3.apk'],
+            allow_cached_props=False),
+         ['split2.apk']),
+        (self.call.device._GetApplicationPathsInternal('test.package'), []),
+        (self.call.adb.InstallMultiple(
+            ['base.apk', 'split2.apk'], partial=None, reinstall=False))):
+      self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
+          ['split1.apk', 'split2.apk', 'split3.apk'], permissions=[], retries=0)
+
+  def testInstallSplitApk_partialInstall(self):
+    with self.assertCalls(
+        (self.call.device._CheckSdkLevel(21)),
+        (mock.call.devil.android.sdk.split_select.SelectSplits(
+            self.device, 'base.apk',
+            ['split1.apk', 'split2.apk', 'split3.apk'],
+            allow_cached_props=False),
+         ['split2.apk']),
+        (self.call.device._GetApplicationPathsInternal('test.package'),
+         ['base-on-device.apk', 'split2-on-device.apk']),
+        (self.call.device._ComputeStaleApks('test.package',
+                                            ['base.apk', 'split2.apk']),
+         (['split2.apk'], None)),
+        (self.call.adb.InstallMultiple(
+            ['split2.apk'], partial='test.package', reinstall=True))):
+      self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
+                                  ['split1.apk', 'split2.apk', 'split3.apk'],
+                                  reinstall=True, permissions=[], retries=0)
+
+
+class DeviceUtilsUninstallTest(DeviceUtilsTest):
+  def testUninstall_callsThrough(self):
+    with self.assertCalls(
+        (self.call.device._GetApplicationPathsInternal('test.package'),
+         ['/path.apk']),
+        self.call.adb.Uninstall('test.package', True)):
+      self.device.Uninstall('test.package', True)
+
+  def testUninstall_noop(self):
+    with self.assertCalls(
+        (self.call.device._GetApplicationPathsInternal('test.package'), [])):
+      self.device.Uninstall('test.package', True)
+
+
+class DeviceUtilsSuTest(DeviceUtilsTest):
+  def testSu_preM(self):
+    with self.patch_call(
+        self.call.device.build_version_sdk,
+        return_value=version_codes.LOLLIPOP_MR1):
+      self.assertEquals('su -c foo', self.device._Su('foo'))
+
+  def testSu_mAndAbove(self):
+    with self.patch_call(
+        self.call.device.build_version_sdk,
+        return_value=version_codes.MARSHMALLOW):
+      self.assertEquals('su 0 foo', self.device._Su('foo'))
+
+
+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.devil.android.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_withHugeCmdAndSU(self):
+    payload = 'hi! ' * 1024
+    expected_cmd_without_su = """sh -c 'echo '"'"'%s'"'"''""" % payload
+    expected_cmd = 'su -c %s' % expected_cmd_without_su
+    with self.assertCalls(
+      (self.call.device.NeedsSU(), True),
+      (self.call.device._Su(expected_cmd_without_su), expected_cmd),
+      (mock.call.devil.android.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):
+    expected_cmd_without_su = "sh -c 'setprop service.adb.root 0'"
+    expected_cmd = 'su -c %s' % expected_cmd_without_su
+    with self.assertCalls(
+        (self.call.device.NeedsSU(), True),
+        (self.call.device._Su(expected_cmd_without_su), expected_cmd),
+        (self.call.adb.Shell(expected_cmd), '')):
+      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.devil.android.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.devil.android.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)
+
+
+@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'], 'some.processing.thing': ['5678']}),
+        (self.call.adb.Shell('kill -9 1234 5678'), '')):
+      self.assertEquals(
+          2, self.device.KillAll('some.process', blocking=False))
+
+  def testKillAll_blocking(self):
+    with self.assertCalls(
+        (self.call.device.GetPids('some.process'),
+         {'some.process': ['1234'], 'some.processing.thing': ['5678']}),
+        (self.call.adb.Shell('kill -9 1234 5678'), ''),
+        (self.call.device.GetPids('some.process'),
+         {'some.processing.thing': ['5678']}),
+        (self.call.device.GetPids('some.process'),
+         {'some.process': ['1111']})): #  Other instance with different pid.
+      self.assertEquals(
+          2, self.device.KillAll('some.process', blocking=True))
+
+  def testKillAll_exactNonblocking(self):
+    with self.assertCalls(
+        (self.call.device.GetPids('some.process'),
+         {'some.process': ['1234'], 'some.processing.thing': ['5678']}),
+        (self.call.adb.Shell('kill -9 1234'), '')):
+      self.assertEquals(
+          1, self.device.KillAll('some.process', exact=True, blocking=False))
+
+  def testKillAll_exactBlocking(self):
+    with self.assertCalls(
+        (self.call.device.GetPids('some.process'),
+         {'some.process': ['1234'], 'some.processing.thing': ['5678']}),
+        (self.call.adb.Shell('kill -9 1234'), ''),
+        (self.call.device.GetPids('some.process'),
+         {'some.process': ['1234'], 'some.processing.thing': ['5678']}),
+        (self.call.device.GetPids('some.process'),
+         {'some.processing.thing': ['5678']})):
+      self.assertEquals(
+          1, self.device.KillAll('some.process', exact=True, 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.device._Su("sh -c 'kill -9 1234'"),
+         "su -c sh -c 'kill -9 1234'"),
+        (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))
+
+  def testKillAll_multipleInstances(self):
+    with self.assertCalls(
+        (self.call.device.GetPids('some.process'),
+            {'some.process': ['1234', '4567']}),
+        (self.call.adb.Shell('kill -15 1234 4567'), '')):
+      self.assertEquals(
+          2, 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='test.package',
+                                activity='.Main')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n 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='test.package',
+                                activity='.Main')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n 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='test.package',
+                                activity='.Main')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-W '
+                            '-a android.intent.action.VIEW '
+                            '-n 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='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 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='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 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='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 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='test.package',
+                                activity='.Main',
+                                extras={'foo': 'test'})
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n 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='test.package',
+                                activity='.Main',
+                                extras={'foo': True})
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n 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='test.package',
+                                activity='.Main',
+                                extras={'foo': 123})
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n 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='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 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='test.package',
+                                activity='.Main')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-S '
+                            '-a android.intent.action.VIEW '
+                            '-n 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='test.package',
+                                activity='.Main',
+                                flags='0x10000000')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n 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(
+            'p=test.package;am instrument "$p"/.TestInstrumentation',
+            check_return=True, large_output=True)):
+      self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=False, raw=False, extras=None)
+
+  def testStartInstrumentation_finish(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            'p=test.package;am instrument -w "$p"/.TestInstrumentation',
+            check_return=True, large_output=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(
+            'p=test.package;am instrument -r "$p"/.TestInstrumentation',
+            check_return=True, large_output=True)):
+      self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=False, raw=True, extras=None)
+
+  def testStartInstrumentation_extras(self):
+    with self.assertCalls(
+        self.call.device.RunShellCommand(
+            'p=test.package;am instrument -e "$p".foo Foo -e bar \'Val \'"$p" '
+            '"$p"/.TestInstrumentation',
+            check_return=True, large_output=True)):
+      self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=False, raw=False, extras={'test.package.foo': 'Foo',
+                                           'bar': 'Val test.package'})
+
+
+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_popupsExist(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True), []),
+        (self.call.device.RunShellCommand(
+            ['am', 'start', '-W', '-a', 'android.intent.action.MAIN',
+            '-c', 'android.intent.category.HOME'], check_return=True),
+         'Starting: Intent { act=android.intent.action.MAIN }\r\n'''),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True), []),
+        (self.call.device.RunShellCommand(
+            ['input', 'keyevent', '66'], check_return=True)),
+        (self.call.device.RunShellCommand(
+            ['input', 'keyevent', '4'], check_return=True)),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True),
+         ['mCurrentFocus Launcher'])):
+      self.device.GoHome()
+
+  def testGoHome_willRetry(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True), []),
+        (self.call.device.RunShellCommand(
+            ['am', 'start', '-W', '-a', 'android.intent.action.MAIN',
+            '-c', 'android.intent.category.HOME'], check_return=True),
+         'Starting: Intent { act=android.intent.action.MAIN }\r\n'''),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True), []),
+        (self.call.device.RunShellCommand(
+            ['input', 'keyevent', '66'], check_return=True,)),
+        (self.call.device.RunShellCommand(
+            ['input', 'keyevent', '4'], check_return=True)),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True), []),
+        (self.call.device.RunShellCommand(
+            ['input', 'keyevent', '66'], check_return=True)),
+        (self.call.device.RunShellCommand(
+            ['input', 'keyevent', '4'], check_return=True)),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True),
+         self.TimeoutError())):
+      with self.assertRaises(device_errors.CommandTimeoutError):
+        self.device.GoHome()
+
+  def testGoHome_alreadyFocused(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True),
+        ['mCurrentFocus Launcher']):
+      self.device.GoHome()
+
+  def testGoHome_alreadyFocusedAlternateCase(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True),
+        [' mCurrentFocus .launcher/.']):
+      self.device.GoHome()
+
+  def testGoHome_obtainsFocusAfterGoingHome(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True), []),
+        (self.call.device.RunShellCommand(
+            ['am', 'start', '-W', '-a', 'android.intent.action.MAIN',
+            '-c', 'android.intent.category.HOME'], check_return=True),
+         'Starting: Intent { act=android.intent.action.MAIN }\r\n'''),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True),
+         ['mCurrentFocus Launcher'])):
+      self.device.GoHome()
+
+class DeviceUtilsForceStopTest(DeviceUtilsTest):
+
+  def testForceStop(self):
+    with self.assertCall(
+        self.call.adb.Shell('p=test.package;if [[ "$(ps)" = *$p* ]]; then '
+                            'am force-stop $p; fi'),
+        ''):
+      self.device.ForceStop('test.package')
+
+
+class DeviceUtilsClearApplicationStateTest(DeviceUtilsTest):
+
+  def testClearApplicationState_setPermissions(self):
+    with self.assertCalls(
+        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'),
+        (self.call.device._GetApplicationPathsInternal('this.package.exists'),
+         ['/data/app/this.package.exists.apk']),
+        (self.call.device.RunShellCommand(
+            ['pm', 'clear', 'this.package.exists'],
+            check_return=True),
+         ['Success']),
+        (self.call.device.GrantPermissions(
+            'this.package.exists', ['p1']), [])):
+      self.device.ClearApplicationState(
+          'this.package.exists', permissions=['p1'])
+
+  def testClearApplicationState_packageDoesntExist(self):
+    with self.assertCalls(
+        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '11'),
+        (self.call.device._GetApplicationPathsInternal('does.not.exist'),
+         [])):
+      self.device.ClearApplicationState('does.not.exist')
+
+  def testClearApplicationState_packageDoesntExistOnAndroidJBMR2OrAbove(self):
+    with self.assertCalls(
+        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'),
+        (self.call.device.RunShellCommand(
+            ['pm', 'clear', 'this.package.does.not.exist'],
+            check_return=True),
+         ['Failed'])):
+      self.device.ClearApplicationState('this.package.does.not.exist')
+
+  def testClearApplicationState_packageExists(self):
+    with self.assertCalls(
+        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'),
+        (self.call.device._GetApplicationPathsInternal('this.package.exists'),
+         ['/data/app/this.package.exists.apk']),
+        (self.call.device.RunShellCommand(
+            ['pm', 'clear', 'this.package.exists'],
+            check_return=True),
+         ['Success'])):
+      self.device.ClearApplicationState('this.package.exists')
+
+  def testClearApplicationState_packageExistsOnAndroidJBMR2OrAbove(self):
+    with self.assertCalls(
+        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'),
+        (self.call.device.RunShellCommand(
+            ['pm', 'clear', 'this.package.exists'],
+            check_return=True),
+         ['Success'])):
+      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_noUnzipCommand(self):
+    test_files = [('/test/host/path/file1', '/test/device/path/file1')]
+    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._MaybeInstallCommands(), False)):
+      self.assertFalse(self.device._PushChangedFilesZipped(test_files,
+                                                           ['/test/dir']))
+
+  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._MaybeInstallCommands(), True),
+        (self.call.device.NeedsSU(), True),
+        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb,
+                                                                 suffix='.zip'),
+             MockTempFile('/test/sdcard/foo123.zip')),
+        self.call.adb.Push(
+            '/test/temp/file/tmp.zip', '/test/sdcard/foo123.zip'),
+        self.call.device.RunShellCommand(
+            'unzip /test/sdcard/foo123.zip&&chmod -R 777 /test/dir',
+            as_root=True,
+            env={'PATH': '/data/local/tmp/bin:$PATH'},
+            check_return=True)):
+      self.assertTrue(self.device._PushChangedFilesZipped(test_files,
+                                                          ['/test/dir']))
+
+  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 DeviceUtilsPathExistsTest(DeviceUtilsTest):
+
+  def testPathExists_usingTest_pathExists(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            "test -e '/path/file exists';echo $?",
+            check_return=True, timeout=None, retries=None), ['0']):
+      self.assertTrue(self.device.PathExists('/path/file exists'))
+
+  def testPathExists_usingTest_multiplePathExists(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            "test -e '/path 1' -a -e /path2;echo $?",
+            check_return=True, timeout=None, retries=None), ['0']):
+      self.assertTrue(self.device.PathExists(('/path 1', '/path2')))
+
+  def testPathExists_usingTest_pathDoesntExist(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            "test -e /path/file.not.exists;echo $?",
+            check_return=True, timeout=None, retries=None), ['1']):
+      self.assertFalse(self.device.PathExists('/path/file.not.exists'))
+
+  def testFileExists_usingTest_pathDoesntExist(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            "test -e /path/file.not.exists;echo $?",
+            check_return=True, timeout=None, retries=None), ['1']):
+      self.assertFalse(self.device.FileExists('/path/file.not.exists'))
+
+
+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.devil.android.device_temp_file.DeviceTempFile(self.adb),
+         MockTempFile('/sdcard/tmp/on.device')),
+        self.call.device.RunShellCommand(
+            'SRC=/this/big/file/can.be.read.with.su DEST=/sdcard/tmp/on.device;'
+            'cp "$SRC" "$DEST" && chmod 666 "$DEST"',
+            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.devil.android.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):
+    expected_cmd_without_su = "sh -c 'echo -n contents > /test/file'"
+    expected_cmd = 'su -c %s' % expected_cmd_without_su
+    with self.assertCalls(
+        (self.call.device.NeedsSU(), True),
+        (self.call.device._Su(expected_cmd_without_su), expected_cmd),
+        (self.call.adb.Shell(expected_cmd),
+         '')):
+      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(self.device.LOCAL_PROPERTIES_PATH),
+         'some.example.prop=with an example value\n'
+         'some.other.prop=value_ok\n'),
+        self.call.device.WriteFile(
+            self.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(self.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(
+            self.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(self.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.device.RunShellCommand(
+            ['getprop', 'test.property'], check_return=True, single_line=True,
+            timeout=self.device._default_timeout,
+            retries=self.device._default_retries),
+        'property_value'):
+      self.assertEqual('property_value',
+                       self.device.GetProp('test.property'))
+
+  def testGetProp_doesNotExist(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['getprop', 'property.does.not.exist'],
+            check_return=True, single_line=True,
+            timeout=self.device._default_timeout,
+            retries=self.device._default_retries),
+        ''):
+      self.assertEqual('', self.device.GetProp('property.does.not.exist'))
+
+  def testGetProp_cachedRoProp(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['getprop'], check_return=True, large_output=True,
+            timeout=self.device._default_timeout,
+            retries=self.device._default_retries),
+        ['[ro.build.type]: [userdebug]']):
+      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.device.RunShellCommand(
+            ['getprop'], check_return=True, large_output=True,
+            timeout=self.device._default_timeout,
+            retries=3),
+         ['[ro.build.type]: [userdebug]'])):
+      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.device.RunShellCommand(
+            ['setprop', 'test.property', 'test value'], check_return=True)):
+      self.device.SetProp('test.property', 'test value')
+
+  def testSetProp_check_succeeds(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['setprop', 'test.property', 'new_value'], check_return=True)),
+        (self.call.device.GetProp('test.property', cache=False), 'new_value')):
+      self.device.SetProp('test.property', 'new_value', check=True)
+
+  def testSetProp_check_fails(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['setprop', 'test.property', 'new_value'], check_return=True)),
+        (self.call.device.GetProp('test.property', cache=False), '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_multipleMatches(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'))
+
+  def testGetPids_multipleInstances(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand('ps | grep -F foo'),
+        ['user  1000    100   1024 1024   ffffffff 00000000 foo',
+         'user  1234    100   1024 1024   ffffffff 00000000 foo']):
+      self.assertEqual(
+          {'foo': ['1000', '1234']},
+          self.device.GetPids('foo'))
+
+
+class DeviceUtilsTakeScreenshotTest(DeviceUtilsTest):
+
+  def testTakeScreenshot_fileNameProvided(self):
+    with self.assertCalls(
+        (mock.call.devil.android.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 DeviceUtilsDismissCrashDialogIfNeededTest(DeviceUtilsTest):
+
+  def testDismissCrashDialogIfNeeded_crashedPageckageNotFound(self):
+    sample_dumpsys_output = '''
+WINDOW MANAGER WINDOWS (dumpsys window windows)
+  Window #11 Window{f8b647a u0 SearchPanel}:
+    mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5
+    mOwnerUid=100 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
+    mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100
+    Requested w=1080 h=1920 mLayoutSeq=426
+    mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000
+'''
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True), sample_dumpsys_output.split('\n'))):
+      package_name = self.device.DismissCrashDialogIfNeeded()
+      self.assertIsNone(package_name)
+
+  def testDismissCrashDialogIfNeeded_crashedPageckageFound(self):
+    sample_dumpsys_output = '''
+WINDOW MANAGER WINDOWS (dumpsys window windows)
+  Window #11 Window{f8b647a u0 SearchPanel}:
+    mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5
+    mOwnerUid=102 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
+    mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100
+    Requested w=1080 h=1920 mLayoutSeq=426
+    mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000
+  mHasPermanentDpad=false
+  mCurrentFocus=Window{3a27740f u0 Application Error: com.android.chrome}
+  mFocusedApp=AppWindowToken{470af6f token=Token{272ec24e ActivityRecord{t894}}}
+'''
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True), sample_dumpsys_output.split('\n')),
+        (self.call.device.RunShellCommand(
+            ['input', 'keyevent', '22'], check_return=True)),
+        (self.call.device.RunShellCommand(
+            ['input', 'keyevent', '22'], check_return=True)),
+        (self.call.device.RunShellCommand(
+            ['input', 'keyevent', '66'], check_return=True)),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'window', 'windows'], check_return=True,
+            large_output=True), [])):
+      package_name = self.device.DismissCrashDialogIfNeeded()
+      self.assertEqual(package_name, 'com.android.chrome')
+
+
+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.assertTrue('test' not in 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 DeviceUtilsHealthyDevicesTest(mock_calls.TestCase):
+
+  def testHealthyDevices_emptyBlacklist(self):
+    test_serials = ['0123456789abcdef', 'fedcba9876543210']
+    with self.assertCalls(
+        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
+         [_AdbWrapperMock(s) for s in test_serials])):
+      blacklist = mock.NonCallableMock(**{'Read.return_value': []})
+      devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
+    for serial, device in zip(test_serials, devices):
+      self.assertTrue(isinstance(device, device_utils.DeviceUtils))
+      self.assertEquals(serial, device.adb.GetDeviceSerial())
+
+  def testHealthyDevices_blacklist(self):
+    test_serials = ['0123456789abcdef', 'fedcba9876543210']
+    with self.assertCalls(
+        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
+         [_AdbWrapperMock(s) for s in test_serials])):
+      blacklist = mock.NonCallableMock(
+          **{'Read.return_value': ['fedcba9876543210']})
+      devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
+    self.assertEquals(1, len(devices))
+    self.assertTrue(isinstance(devices[0], device_utils.DeviceUtils))
+    self.assertEquals('0123456789abcdef', devices[0].adb.GetDeviceSerial())
+
+
+class DeviceUtilsRestartAdbdTest(DeviceUtilsTest):
+
+  def testAdbdRestart(self):
+    mock_temp_file = '/sdcard/temp-123.sh'
+    with self.assertCalls(
+        (mock.call.devil.android.device_temp_file.DeviceTempFile(
+            self.adb, suffix='.sh'), MockTempFile(mock_temp_file)),
+        self.call.device.WriteFile(mock.ANY, mock.ANY),
+        (self.call.device.RunShellCommand(
+            ['source', mock_temp_file], as_root=True)),
+        self.call.adb.WaitForDevice()):
+      self.device.RestartAdbd()
+
+
+class DeviceUtilsGrantPermissionsTest(DeviceUtilsTest):
+
+  def testGrantPermissions_none(self):
+    self.device.GrantPermissions('package', [])
+
+  def testGrantPermissions_underM(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.LOLLIPOP):
+      self.device.GrantPermissions('package', ['p1'])
+
+  def testGrantPermissions_one(self):
+    permissions_cmd = 'pm grant package p1'
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.MARSHMALLOW):
+      with self.assertCalls(
+          (self.call.device.RunShellCommand(permissions_cmd), [])):
+        self.device.GrantPermissions('package', ['p1'])
+
+  def testGrantPermissions_multiple(self):
+    permissions_cmd = 'pm grant package p1;pm grant package p2'
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.MARSHMALLOW):
+      with self.assertCalls(
+          (self.call.device.RunShellCommand(permissions_cmd), [])):
+        self.device.GrantPermissions('package', ['p1', 'p2'])
+
+  def testGrantPermissions_WriteExtrnalStorage(self):
+    permissions_cmd = (
+        'pm grant package android.permission.WRITE_EXTERNAL_STORAGE;'
+        'pm grant package android.permission.READ_EXTERNAL_STORAGE')
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.MARSHMALLOW):
+      with self.assertCalls(
+          (self.call.device.RunShellCommand(permissions_cmd), [])):
+        self.device.GrantPermissions(
+            'package', ['android.permission.WRITE_EXTERNAL_STORAGE'])
+
+  def testGrantPermissions_BlackList(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.MARSHMALLOW):
+        self.device.GrantPermissions(
+            'package', ['android.permission.ACCESS_MOCK_LOCATION'])
+
+
+class DeviecUtilsIsScreenOn(DeviceUtilsTest):
+
+  _L_SCREEN_ON = ['test=test mInteractive=true']
+  _K_SCREEN_ON = ['test=test mScreenOn=true']
+  _L_SCREEN_OFF = ['mInteractive=false']
+  _K_SCREEN_OFF = ['mScreenOn=false']
+
+  def testIsScreenOn_onPreL(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.KITKAT):
+      with self.assertCalls(
+          (self.call.device._RunPipedShellCommand(
+              'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_ON)):
+        self.assertTrue(self.device.IsScreenOn())
+
+  def testIsScreenOn_onL(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.LOLLIPOP):
+      with self.assertCalls(
+          (self.call.device._RunPipedShellCommand(
+              'dumpsys input_method | grep mInteractive'), self._L_SCREEN_ON)):
+        self.assertTrue(self.device.IsScreenOn())
+
+  def testIsScreenOn_offPreL(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.KITKAT):
+      with self.assertCalls(
+          (self.call.device._RunPipedShellCommand(
+              'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_OFF)):
+        self.assertFalse(self.device.IsScreenOn())
+
+  def testIsScreenOn_offL(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.LOLLIPOP):
+      with self.assertCalls(
+          (self.call.device._RunPipedShellCommand(
+              'dumpsys input_method | grep mInteractive'), self._L_SCREEN_OFF)):
+        self.assertFalse(self.device.IsScreenOn())
+
+  def testIsScreenOn_noOutput(self):
+    with self.patch_call(self.call.device.build_version_sdk,
+                         return_value=version_codes.LOLLIPOP):
+      with self.assertCalls(
+          (self.call.device._RunPipedShellCommand(
+              'dumpsys input_method | grep mInteractive'), [])):
+        with self.assertRaises(device_errors.CommandFailedError):
+          self.device.IsScreenOn()
+
+
+class DeviecUtilsSetScreen(DeviceUtilsTest):
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetScren_alreadySet(self):
+    with self.assertCalls(
+        (self.call.device.IsScreenOn(), False)):
+      self.device.SetScreen(False)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetScreen_on(self):
+    with self.assertCalls(
+        (self.call.device.IsScreenOn(), False),
+        (self.call.device.RunShellCommand('input keyevent 26'), []),
+        (self.call.device.IsScreenOn(), True)):
+      self.device.SetScreen(True)
+
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetScreen_off(self):
+    with self.assertCalls(
+        (self.call.device.IsScreenOn(), True),
+        (self.call.device.RunShellCommand('input keyevent 26'), []),
+        (self.call.device.IsScreenOn(), False)):
+      self.device.SetScreen(False)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetScreen_slow(self):
+    with self.assertCalls(
+        (self.call.device.IsScreenOn(), True),
+        (self.call.device.RunShellCommand('input keyevent 26'), []),
+        (self.call.device.IsScreenOn(), True),
+        (self.call.device.IsScreenOn(), True),
+        (self.call.device.IsScreenOn(), False)):
+      self.device.SetScreen(False)
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
diff --git a/build/android/devil/android/fastboot_utils.py b/build/android/devil/android/fastboot_utils.py
new file mode 100644
index 0000000..587f42f
--- /dev/null
+++ b/build/android/devil/android/fastboot_utils.py
@@ -0,0 +1,245 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Provides a variety of device interactions based on fastboot."""
+# pylint: disable=unused-argument
+
+import contextlib
+import fnmatch
+import logging
+import os
+import re
+
+from devil.android import decorators
+from devil.android import device_errors
+from devil.android.sdk import fastboot
+from devil.utils import timeout_retry
+
+_DEFAULT_TIMEOUT = 30
+_DEFAULT_RETRIES = 3
+_FASTBOOT_REBOOT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
+ALL_PARTITIONS = [
+    'bootloader',
+    'radio',
+    'boot',
+    'recovery',
+    'system',
+    'userdata',
+    'cache',
+]
+
+class FastbootUtils(object):
+
+  _FASTBOOT_WAIT_TIME = 1
+  _RESTART_WHEN_FLASHING = ['bootloader', 'radio']
+  _BOARD_VERIFICATION_FILE = 'android-info.txt'
+  _FLASH_IMAGE_FILES = {
+      'bootloader': 'bootloader*.img',
+      'radio': 'radio*.img',
+      'boot': 'boot.img',
+      'recovery': 'recovery.img',
+      'system': 'system.img',
+      'userdata': 'userdata.img',
+      'cache': 'cache.img',
+  }
+
+  def __init__(self, device, fastbooter=None, default_timeout=_DEFAULT_TIMEOUT,
+               default_retries=_DEFAULT_RETRIES):
+    """FastbootUtils constructor.
+
+    Example Usage to flash a device:
+      fastboot = fastboot_utils.FastbootUtils(device)
+      fastboot.FlashDevice('/path/to/build/directory')
+
+    Args:
+      device: A DeviceUtils instance.
+      fastbooter: Optional fastboot object. If none is passed, one will
+        be created.
+      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._device = device
+    self._board = device.product_board
+    self._serial = str(device)
+    self._default_timeout = default_timeout
+    self._default_retries = default_retries
+    if fastbooter:
+      self.fastboot = fastbooter
+    else:
+      self.fastboot = fastboot.Fastboot(self._serial)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def WaitForFastbootMode(self, timeout=None, retries=None):
+    """Wait for device to boot into fastboot mode.
+
+    This waits for the device serial to show up in fastboot devices output.
+    """
+    def fastboot_mode():
+      return self._serial in self.fastboot.Devices()
+
+    timeout_retry.WaitFor(fastboot_mode, wait_period=self._FASTBOOT_WAIT_TIME)
+
+  @decorators.WithTimeoutAndRetriesFromInstance(
+      min_default_timeout=_FASTBOOT_REBOOT_TIMEOUT)
+  def EnableFastbootMode(self, timeout=None, retries=None):
+    """Reboots phone into fastboot mode.
+
+    Roots phone if needed, then reboots phone into fastboot mode and waits.
+    """
+    self._device.EnableRoot()
+    self._device.adb.Reboot(to_bootloader=True)
+    self.WaitForFastbootMode()
+
+  @decorators.WithTimeoutAndRetriesFromInstance(
+      min_default_timeout=_FASTBOOT_REBOOT_TIMEOUT)
+  def Reboot(self, bootloader=False, timeout=None, retries=None):
+    """Reboots out of fastboot mode.
+
+    It reboots the phone either back into fastboot, or to a regular boot. It
+    then blocks until the device is ready.
+
+    Args:
+      bootloader: If set to True, reboots back into bootloader.
+    """
+    if bootloader:
+      self.fastboot.RebootBootloader()
+      self.WaitForFastbootMode()
+    else:
+      self.fastboot.Reboot()
+      self._device.WaitUntilFullyBooted(timeout=_FASTBOOT_REBOOT_TIMEOUT)
+
+  def _VerifyBoard(self, directory):
+    """Validate as best as possible that the android build matches the device.
+
+    Goes through build files and checks if the board name is mentioned in the
+    |self._BOARD_VERIFICATION_FILE| or in the build archive.
+
+    Args:
+      directory: directory where build files are located.
+    """
+    files = os.listdir(directory)
+    board_regex = re.compile(r'require board=(\w+)')
+    if self._BOARD_VERIFICATION_FILE in files:
+      with open(os.path.join(directory, self._BOARD_VERIFICATION_FILE)) as f:
+        for line in f:
+          m = board_regex.match(line)
+          if m:
+            board_name = m.group(1)
+            if board_name == self._board:
+              return True
+            elif board_name:
+              return False
+            else:
+              logging.warning('No board type found in %s.',
+                              self._BOARD_VERIFICATION_FILE)
+    else:
+      logging.warning('%s not found. Unable to use it to verify device.',
+                      self._BOARD_VERIFICATION_FILE)
+
+    zip_regex = re.compile(r'.*%s.*\.zip' % re.escape(self._board))
+    for f in files:
+      if zip_regex.match(f):
+        return True
+
+    return False
+
+  def _FindAndVerifyPartitionsAndImages(self, partitions, directory):
+    """Validate partitions and images.
+
+    Validate all partition names and partition directories. Cannot stop mid
+    flash so its important to validate everything first.
+
+    Args:
+      Partitions: partitions to be tested.
+      directory: directory containing the images.
+
+    Returns:
+      Dictionary with exact partition, image name mapping.
+    """
+    files = os.listdir(directory)
+
+    def find_file(pattern):
+      for filename in files:
+        if fnmatch.fnmatch(filename, pattern):
+          return os.path.join(directory, filename)
+      raise device_errors.FastbootCommandFailedError(
+          'Failed to flash device. Counld not find image for %s.', pattern)
+
+    return {name: find_file(self._FLASH_IMAGE_FILES[name])
+            for name in partitions}
+
+  def _FlashPartitions(self, partitions, directory, wipe=False, force=False):
+    """Flashes all given partiitons with all given images.
+
+    Args:
+      partitions: List of partitions to flash.
+      directory: Directory where all partitions can be found.
+      wipe: If set to true, will automatically detect if cache and userdata
+          partitions are sent, and if so ignore them.
+      force: boolean to decide to ignore board name safety checks.
+
+    Raises:
+      device_errors.CommandFailedError(): If image cannot be found or if bad
+          partition name is give.
+    """
+    if not self._VerifyBoard(directory):
+      if force:
+        logging.warning('Could not verify build is meant to be installed on '
+                        'the current device type, but force flag is set. '
+                        'Flashing device. Possibly dangerous operation.')
+      else:
+        raise device_errors.CommandFailedError(
+            'Could not verify build is meant to be installed on the current '
+            'device type. Run again with force=True to force flashing with an '
+            'unverified board.')
+
+    flash_image_files = self._FindAndVerifyPartitionsAndImages(partitions,
+                                                               directory)
+    for partition in partitions:
+      if partition in ['cache', 'userdata'] and not wipe:
+        logging.info(
+            'Not flashing in wipe mode. Skipping partition %s.', partition)
+      else:
+        logging.info(
+            'Flashing %s with %s', partition, flash_image_files[partition])
+        self.fastboot.Flash(partition, flash_image_files[partition])
+        if partition in self._RESTART_WHEN_FLASHING:
+          self.Reboot(bootloader=True)
+
+  @contextlib.contextmanager
+  def FastbootMode(self, timeout=None, retries=None):
+    """Context manager that enables fastboot mode, and reboots after.
+
+    Example usage:
+      with FastbootMode():
+        Flash Device
+      # Anything that runs after flashing.
+    """
+    self.EnableFastbootMode()
+    self.fastboot.SetOemOffModeCharge(False)
+    try:
+      yield self
+    finally:
+      self.fastboot.SetOemOffModeCharge(True)
+      self.Reboot()
+
+  def FlashDevice(self, directory, partitions=None, wipe=False):
+    """Flash device with build in |directory|.
+
+    Directory must contain bootloader, radio, boot, recovery, system, userdata,
+    and cache .img files from an android build. This is a dangerous operation so
+    use with care.
+
+    Args:
+      fastboot: A FastbootUtils instance.
+      directory: Directory with build files.
+      wipe: Wipes cache and userdata if set to true.
+      partitions: List of partitions to flash. Defaults to all.
+    """
+    if partitions is None:
+      partitions = ALL_PARTITIONS
+    with self.FastbootMode():
+      self._FlashPartitions(partitions, directory, wipe=wipe)
diff --git a/build/android/devil/android/fastboot_utils_test.py b/build/android/devil/android/fastboot_utils_test.py
new file mode 100755
index 0000000..ff2c501
--- /dev/null
+++ b/build/android/devil/android/fastboot_utils_test.py
@@ -0,0 +1,281 @@
+#!/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 fastboot_utils.py
+"""
+
+# pylint: disable=protected-access,unused-argument
+
+import io
+import logging
+import os
+import sys
+import unittest
+
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.android import fastboot_utils
+from devil.android.sdk import fastboot
+from devil.utils import mock_calls
+from pylib import constants
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=import-error
+
+_BOARD = 'board_type'
+_SERIAL = '0123456789abcdef'
+_PARTITIONS = ['cache', 'userdata', 'system', 'bootloader', 'radio']
+_IMAGES = {
+    'cache': 'cache.img',
+    'userdata': 'userdata.img',
+    'system': 'system.img',
+    'bootloader': 'bootloader.img',
+    'radio': 'radio.img',
+}
+_VALID_FILES = [_BOARD + '.zip', 'android-info.txt']
+_INVALID_FILES = ['test.zip', 'android-info.txt']
+
+
+class MockFile(object):
+
+  def __init__(self, name='/tmp/some/file'):
+    self.file = mock.MagicMock(spec=file)
+    self.file.name = 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
+
+
+def _FastbootWrapperMock(test_serial):
+  fastbooter = mock.Mock(spec=fastboot.Fastboot)
+  fastbooter.__str__ = mock.Mock(return_value=test_serial)
+  fastbooter.Devices.return_value = [test_serial]
+  return fastbooter
+
+def _DeviceUtilsMock(test_serial):
+  device = mock.Mock(spec=device_utils.DeviceUtils)
+  device.__str__ = mock.Mock(return_value=test_serial)
+  device.product_board = mock.Mock(return_value=_BOARD)
+  device.adb = mock.Mock()
+  return device
+
+
+class FastbootUtilsTest(mock_calls.TestCase):
+
+  def setUp(self):
+    self.device_utils_mock = _DeviceUtilsMock(_SERIAL)
+    self.fastboot_wrapper = _FastbootWrapperMock(_SERIAL)
+    self.fastboot = fastboot_utils.FastbootUtils(
+        self.device_utils_mock, fastbooter=self.fastboot_wrapper,
+        default_timeout=2, default_retries=0)
+    self.fastboot._board = _BOARD
+
+
+class FastbootUtilsInitTest(FastbootUtilsTest):
+
+  def testInitWithDeviceUtil(self):
+    f = fastboot_utils.FastbootUtils(self.device_utils_mock)
+    self.assertEqual(str(self.device_utils_mock), str(f._device))
+
+  def testInitWithMissing_fails(self):
+    with self.assertRaises(AttributeError):
+      fastboot_utils.FastbootUtils(None)
+    with self.assertRaises(AttributeError):
+      fastboot_utils.FastbootUtils('')
+
+
+class FastbootUtilsWaitForFastbootMode(FastbootUtilsTest):
+
+  # If this test fails by timing out after 1 second.
+  @mock.patch('time.sleep', mock.Mock())
+  def testWaitForFastbootMode(self):
+    self.fastboot.WaitForFastbootMode()
+
+
+class FastbootUtilsEnableFastbootMode(FastbootUtilsTest):
+
+  def testEnableFastbootMode(self):
+    with self.assertCalls(
+        self.call.fastboot._device.EnableRoot(),
+        self.call.fastboot._device.adb.Reboot(to_bootloader=True),
+        self.call.fastboot.WaitForFastbootMode()):
+      self.fastboot.EnableFastbootMode()
+
+
+class FastbootUtilsReboot(FastbootUtilsTest):
+
+  def testReboot_bootloader(self):
+    with self.assertCalls(
+        self.call.fastboot.fastboot.RebootBootloader(),
+        self.call.fastboot.WaitForFastbootMode()):
+      self.fastboot.Reboot(bootloader=True)
+
+  def testReboot_normal(self):
+    with self.assertCalls(
+        self.call.fastboot.fastboot.Reboot(),
+        self.call.fastboot._device.WaitUntilFullyBooted(timeout=mock.ANY)):
+      self.fastboot.Reboot()
+
+
+class FastbootUtilsFlashPartitions(FastbootUtilsTest):
+
+  def testFlashPartitions_wipe(self):
+    with self.assertCalls(
+        (self.call.fastboot._VerifyBoard('test'), True),
+        (self.call.fastboot._FindAndVerifyPartitionsAndImages(
+            _PARTITIONS, 'test'), _IMAGES),
+        (self.call.fastboot.fastboot.Flash('cache', 'cache.img')),
+        (self.call.fastboot.fastboot.Flash('userdata', 'userdata.img')),
+        (self.call.fastboot.fastboot.Flash('system', 'system.img')),
+        (self.call.fastboot.fastboot.Flash('bootloader', 'bootloader.img')),
+        (self.call.fastboot.Reboot(bootloader=True)),
+        (self.call.fastboot.fastboot.Flash('radio', 'radio.img')),
+        (self.call.fastboot.Reboot(bootloader=True))):
+      self.fastboot._FlashPartitions(_PARTITIONS, 'test', wipe=True)
+
+  def testFlashPartitions_noWipe(self):
+    with self.assertCalls(
+        (self.call.fastboot._VerifyBoard('test'), True),
+        (self.call.fastboot._FindAndVerifyPartitionsAndImages(
+            _PARTITIONS, 'test'), _IMAGES),
+        (self.call.fastboot.fastboot.Flash('system', 'system.img')),
+        (self.call.fastboot.fastboot.Flash('bootloader', 'bootloader.img')),
+        (self.call.fastboot.Reboot(bootloader=True)),
+        (self.call.fastboot.fastboot.Flash('radio', 'radio.img')),
+        (self.call.fastboot.Reboot(bootloader=True))):
+      self.fastboot._FlashPartitions(_PARTITIONS, 'test')
+
+
+class FastbootUtilsFastbootMode(FastbootUtilsTest):
+
+  def testFastbootMode_good(self):
+    with self.assertCalls(
+        self.call.fastboot.EnableFastbootMode(),
+        self.call.fastboot.fastboot.SetOemOffModeCharge(False),
+        self.call.fastboot.fastboot.SetOemOffModeCharge(True),
+        self.call.fastboot.Reboot()):
+      with self.fastboot.FastbootMode() as fbm:
+        self.assertEqual(self.fastboot, fbm)
+
+  def testFastbootMode_exception(self):
+    with self.assertCalls(
+        self.call.fastboot.EnableFastbootMode(),
+        self.call.fastboot.fastboot.SetOemOffModeCharge(False),
+        self.call.fastboot.fastboot.SetOemOffModeCharge(True),
+        self.call.fastboot.Reboot()):
+      with self.assertRaises(NotImplementedError):
+        with self.fastboot.FastbootMode() as fbm:
+          self.assertEqual(self.fastboot, fbm)
+          raise NotImplementedError
+
+  def testFastbootMode_exceptionInEnableFastboot(self):
+    self.fastboot.EnableFastbootMode = mock.Mock()
+    self.fastboot.EnableFastbootMode.side_effect = NotImplementedError
+    with self.assertRaises(NotImplementedError):
+      with self.fastboot.FastbootMode():
+        pass
+
+
+class FastbootUtilsVerifyBoard(FastbootUtilsTest):
+
+  def testVerifyBoard_bothValid(self):
+    mock_file = io.StringIO(u'require board=%s\n' % _BOARD)
+    with mock.patch('__builtin__.open', return_value=mock_file, create=True):
+      with mock.patch('os.listdir', return_value=_VALID_FILES):
+        self.assertTrue(self.fastboot._VerifyBoard('test'))
+
+  def testVerifyBoard_BothNotValid(self):
+    mock_file = io.StringIO(u'abc')
+    with mock.patch('__builtin__.open', return_value=mock_file, create=True):
+      with mock.patch('os.listdir', return_value=_INVALID_FILES):
+        self.assertFalse(self.assertFalse(self.fastboot._VerifyBoard('test')))
+
+  def testVerifyBoard_FileNotFoundZipValid(self):
+    with mock.patch('os.listdir', return_value=[_BOARD + '.zip']):
+      self.assertTrue(self.fastboot._VerifyBoard('test'))
+
+  def testVerifyBoard_ZipNotFoundFileValid(self):
+    mock_file = io.StringIO(u'require board=%s\n' % _BOARD)
+    with mock.patch('__builtin__.open', return_value=mock_file, create=True):
+      with mock.patch('os.listdir', return_value=['android-info.txt']):
+        self.assertTrue(self.fastboot._VerifyBoard('test'))
+
+  def testVerifyBoard_zipNotValidFileIs(self):
+    mock_file = io.StringIO(u'require board=%s\n' % _BOARD)
+    with mock.patch('__builtin__.open', return_value=mock_file, create=True):
+      with mock.patch('os.listdir', return_value=_INVALID_FILES):
+        self.assertTrue(self.fastboot._VerifyBoard('test'))
+
+  def testVerifyBoard_fileNotValidZipIs(self):
+    mock_file = io.StringIO(u'require board=WrongBoard')
+    with mock.patch('__builtin__.open', return_value=mock_file, create=True):
+      with mock.patch('os.listdir', return_value=_VALID_FILES):
+        self.assertFalse(self.fastboot._VerifyBoard('test'))
+
+  def testVerifyBoard_noBoardInFileValidZip(self):
+    mock_file = io.StringIO(u'Regex wont match')
+    with mock.patch('__builtin__.open', return_value=mock_file, create=True):
+      with mock.patch('os.listdir', return_value=_VALID_FILES):
+        self.assertTrue(self.fastboot._VerifyBoard('test'))
+
+  def testVerifyBoard_noBoardInFileInvalidZip(self):
+    mock_file = io.StringIO(u'Regex wont match')
+    with mock.patch('__builtin__.open', return_value=mock_file, create=True):
+      with mock.patch('os.listdir', return_value=_INVALID_FILES):
+        self.assertFalse(self.fastboot._VerifyBoard('test'))
+
+class FastbootUtilsFindAndVerifyPartitionsAndImages(FastbootUtilsTest):
+
+  def testFindAndVerifyPartitionsAndImages_valid(self):
+    PARTITIONS = [
+        'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata', 'cache'
+    ]
+    files = [
+        'bootloader-test-.img',
+        'radio123.img',
+        'boot.img',
+        'recovery.img',
+        'system.img',
+        'userdata.img',
+        'cache.img'
+    ]
+    return_check = {
+      'bootloader': 'test/bootloader-test-.img',
+      'radio': 'test/radio123.img',
+      'boot': 'test/boot.img',
+      'recovery': 'test/recovery.img',
+      'system': 'test/system.img',
+      'userdata': 'test/userdata.img',
+      'cache': 'test/cache.img',
+    }
+
+    with mock.patch('os.listdir', return_value=files):
+      return_value = self.fastboot._FindAndVerifyPartitionsAndImages(
+          PARTITIONS, 'test')
+      self.assertDictEqual(return_value, return_check)
+
+  def testFindAndVerifyPartitionsAndImages_badPartition(self):
+    with mock.patch('os.listdir', return_value=['test']):
+      with self.assertRaises(KeyError):
+        self.fastboot._FindAndVerifyPartitionsAndImages(['test'], 'test')
+
+  def testFindAndVerifyPartitionsAndImages_noFile(self):
+    with mock.patch('os.listdir', return_value=['test']):
+      with self.assertRaises(device_errors.FastbootCommandFailedError):
+        self.fastboot._FindAndVerifyPartitionsAndImages(['cache'], 'test')
+
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
diff --git a/build/android/devil/android/logcat_monitor.py b/build/android/devil/android/logcat_monitor.py
new file mode 100644
index 0000000..d162230
--- /dev/null
+++ b/build/android/devil/android/logcat_monitor.py
@@ -0,0 +1,134 @@
+# Copyright 2015 The Chromium 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 logging
+import re
+
+from devil.android import decorators
+from devil.android.sdk import adb_wrapper
+
+
+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:]+'
+    # pylint: disable=protected-access
+    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/devil/android/logcat_monitor_test.py
similarity index 90%
rename from build/android/pylib/device/logcat_monitor_test.py
rename to build/android/devil/android/logcat_monitor_test.py
index db397e5..2b7969c 100755
--- a/build/android/pylib/device/logcat_monitor_test.py
+++ b/build/android/devil/android/logcat_monitor_test.py
@@ -3,21 +3,29 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# pylint: disable=protected-access
+
 import itertools
 import os
 import sys
 import unittest
 
+from devil.android import logcat_monitor
+from devil.android.sdk import adb_wrapper
 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
 
 
+def _CreateTestLog(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
+
+
 class LogcatMonitorTest(unittest.TestCase):
 
   _TEST_THREADTIME_LOGCAT_DATA = [
@@ -36,12 +44,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(
@@ -62,7 +64,7 @@
       next(expected_iter)
 
   def testWaitFor_success(self):
-    test_log = self._createTestLog(
+    test_log = _CreateTestLog(
         raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
     actual_match = test_log.WaitFor(r'.*(fatal|error) logcat monitor.*', None)
     self.assertTrue(actual_match)
@@ -73,14 +75,14 @@
     self.assertEqual('error', actual_match.group(1))
 
   def testWaitFor_failure(self):
-    test_log = self._createTestLog(
+    test_log = _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(
+    test_log = _CreateTestLog(
         raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
     expected_results = [
         ('7890', '0987', 'V', 'LogcatMonitorTest',
@@ -99,14 +101,14 @@
     self.assertIterEqual(iter(expected_results), actual_results)
 
   def testFindAll_defaults_miss(self):
-    test_log = self._createTestLog(
+    test_log = _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(
+    test_log = _CreateTestLog(
         raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
     actual_results = test_log.FindAll(
         r'\S* logcat monitor test message \d', proc_id=1234)
@@ -116,7 +118,7 @@
     self.assertIterEqual(iter(expected_results), actual_results)
 
   def testFindAll_filterThreadId(self):
-    test_log = self._createTestLog(
+    test_log = _CreateTestLog(
         raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
     actual_results = test_log.FindAll(
         r'\S* logcat monitor test message \d', thread_id=2109)
@@ -126,7 +128,7 @@
     self.assertIterEqual(iter(expected_results), actual_results)
 
   def testFindAll_filterLogLevel(self):
-    test_log = self._createTestLog(
+    test_log = _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]')
@@ -138,7 +140,7 @@
     self.assertIterEqual(iter(expected_results), actual_results)
 
   def testFindAll_filterComponent(self):
-    test_log = self._createTestLog(
+    test_log = _CreateTestLog(
         raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
     actual_results = test_log.FindAll(r'.*', component='LogcatMonitorTest')
     expected_results = [
diff --git a/build/android/devil/android/md5sum.py b/build/android/devil/android/md5sum.py
new file mode 100644
index 0000000..dbd988f
--- /dev/null
+++ b/build/android/devil/android/md5sum.py
@@ -0,0 +1,110 @@
+# Copyright 2014 The Chromium 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 posixpath
+import re
+
+from devil.android import device_errors
+from devil.utils import cmd_helper
+from pylib import constants
+
+MD5SUM_DEVICE_LIB_PATH = '/data/local/tmp/md5sum'
+MD5SUM_DEVICE_BIN_PATH = MD5SUM_DEVICE_LIB_PATH + '/md5sum_bin'
+
+_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|.
+
+  Directories are traversed recursively and the MD5 sum of each file found is
+  reported in the result.
+
+  Args:
+    paths: A list of host paths to md5sum.
+  Returns:
+    A dict mapping file 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|.
+
+  Directories are traversed recursively and the MD5 sum of each file found is
+  reported in the result.
+
+  Args:
+    paths: A list of device paths to md5sum.
+  Returns:
+    A dict mapping file paths to their respective md5sum checksums.
+  """
+  if not paths:
+    return {}
+
+  if isinstance(paths, basestring):
+    paths = [paths]
+  # Allow generators
+  paths = list(paths)
+
+  md5sum_dist_path = os.path.join(constants.GetOutDirectory(), 'md5sum_dist')
+  md5sum_dist_bin_path = os.path.join(md5sum_dist_path, 'md5sum_bin')
+
+  if not os.path.exists(md5sum_dist_path):
+    raise IOError('File not built: %s' % md5sum_dist_path)
+  md5sum_file_size = os.path.getsize(md5sum_dist_bin_path)
+
+  # For better performance, make the script as small as possible to try and
+  # avoid needing to write to an intermediary file (which RunShellCommand will
+  # do if necessary).
+  md5sum_script = 'a=%s;' % MD5SUM_DEVICE_BIN_PATH
+  # Check if the binary is missing or has changed (using its file size as an
+  # indicator), and trigger a (re-)push via the exit code.
+  md5sum_script += '! [[ $(ls -l $a) = *%d* ]]&&exit 2;' % md5sum_file_size
+  # Make sure it can find libbase.so
+  md5sum_script += 'export LD_LIBRARY_PATH=%s;' % MD5SUM_DEVICE_LIB_PATH
+  if len(paths) > 1:
+    prefix = posixpath.commonprefix(paths)
+    if len(prefix) > 4:
+      md5sum_script += 'p="%s";' % prefix
+      paths = ['$p"%s"' % p[len(prefix):] for p in paths]
+
+  md5sum_script += ';'.join('$a %s' % p for p in paths)
+  # Don't fail the script if the last md5sum fails (due to file not found)
+  # Note: ":" is equivalent to "true".
+  md5sum_script += ';:'
+  try:
+    out = device.RunShellCommand(md5sum_script, check_return=True)
+  except device_errors.AdbShellCommandFailedError as e:
+    # Push the binary only if it is found to not exist
+    # (faster than checking up-front).
+    if e.status == 2:
+      # If files were previously pushed as root (adbd running as root), trying
+      # to re-push as non-root causes the push command to report success, but
+      # actually fail. So, wipe the directory first.
+      device.RunShellCommand(['rm', '-rf', MD5SUM_DEVICE_LIB_PATH],
+                             as_root=True, check_return=True)
+      device.adb.Push(md5sum_dist_path, MD5SUM_DEVICE_LIB_PATH)
+      out = device.RunShellCommand(md5sum_script, check_return=True)
+    else:
+      raise
+
+  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/devil/android/md5sum_test.py
similarity index 67%
rename from build/android/pylib/utils/md5sum_test.py
rename to build/android/devil/android/md5sum_test.py
index 5bdee32..e9481b6 100755
--- a/build/android/pylib/utils/md5sum_test.py
+++ b/build/android/devil/android/md5sum_test.py
@@ -7,13 +7,13 @@
 import sys
 import unittest
 
-from pylib import cmd_helper
+from devil.android import device_errors
+from devil.android import md5sum
 from pylib import constants
-from pylib.utils import md5sum
 
 sys.path.append(
     os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
-import mock
+import mock # pylint: disable=import-error
 
 TEST_OUT_DIR = os.path.join('test', 'out', 'directory')
 HOST_MD5_EXECUTABLE = os.path.join(TEST_OUT_DIR, 'md5sum_bin_host')
@@ -38,7 +38,8 @@
     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):
+    with mock.patch('devil.utils.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)
@@ -52,7 +53,8 @@
     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):
+    with mock.patch('devil.utils.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)
@@ -70,7 +72,8 @@
     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):
+    with mock.patch('devil.utils.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)
@@ -82,44 +85,35 @@
       mock_get_cmd_output.assert_called_once_with(
           [HOST_MD5_EXECUTABLE, '/test/host/file0.dat', '/test/host/file1.dat'])
 
+  def testCalculateDeviceMd5Sums_noPaths(self):
+    device = mock.NonCallableMock()
+    device.RunShellCommand = mock.Mock(side_effect=Exception())
+
+    out = md5sum.CalculateDeviceMd5Sums([], device)
+    self.assertEquals(0, len(out))
+
   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)):
+    with mock.patch('os.path.getsize', return_value=1337):
       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'])
+      self.assertEquals(1, len(device.RunShellCommand.call_args_list))
 
   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',
@@ -128,16 +122,7 @@
     ]
     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)):
+    with mock.patch('os.path.getsize', return_value=1337):
       out = md5sum.CalculateDeviceMd5Sums(test_path, device)
       self.assertEquals(2, len(out))
       self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out)
@@ -146,18 +131,13 @@
       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'])
+      self.assertEquals(1, len(device.RunShellCommand.call_args_list))
 
   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',
@@ -166,16 +146,7 @@
     ]
     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)):
+    with mock.patch('os.path.getsize', return_value=1337):
       out = md5sum.CalculateDeviceMd5Sums(test_path, device)
       self.assertEquals(2, len(out))
       self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out)
@@ -184,45 +155,77 @@
       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'])
+      self.assertEquals(1, len(device.RunShellCommand.call_args_list))
 
   def testCalculateDeviceMd5Sums_singlePath_linkerWarning(self):
     # See crbug/479966
     test_path = '/storage/emulated/legacy/test/file.dat'
 
     device = mock.NonCallableMock()
+    device_md5sum_output = [
+        'WARNING: linker: /data/local/tmp/md5sum/md5sum_bin: '
+            'unused DT entry: type 0x1d arg 0x15db',
+        'THIS_IS_NOT_A_VALID_CHECKSUM_ZZZ some random text',
+        '0123456789abcdeffedcba9876543210 '
+            '/storage/emulated/legacy/test/file.dat',
+    ]
+    device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
+
+    with mock.patch('os.path.getsize', return_value=1337):
+      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'])
+      self.assertEquals(1, len(device.RunShellCommand.call_args_list))
+
+  def testCalculateDeviceMd5Sums_list_fileMissing(self):
+    test_path = ['/storage/emulated/legacy/test/file0.dat',
+                 '/storage/emulated/legacy/test/file1.dat']
+    device = mock.NonCallableMock()
+    device_md5sum_output = [
+        '0123456789abcdeffedcba9876543210 '
+            '/storage/emulated/legacy/test/file0.dat',
+        '[0819/203513:ERROR:md5sum.cc(25)] Could not open file asdf',
+        '',
+    ]
+    device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
+
+    with mock.patch('os.path.getsize', return_value=1337):
+      out = md5sum.CalculateDeviceMd5Sums(test_path, device)
+      self.assertEquals(1, len(out))
+      self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out)
+      self.assertEquals('0123456789abcdeffedcba9876543210',
+                        out['/storage/emulated/legacy/test/file0.dat'])
+      self.assertEquals(1, len(device.RunShellCommand.call_args_list))
+
+
+  def testCalculateDeviceMd5Sums_requiresBinary(self):
+    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',
+        'THIS_IS_NOT_A_VALID_CHECKSUM_ZZZ some random text',
         '0123456789abcdeffedcba9876543210 '
             '/storage/emulated/legacy/test/file.dat',
     ]
-    device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
+    error = device_errors.AdbShellCommandFailedError('cmd', 'out', 2)
+    device.RunShellCommand = mock.Mock(
+        side_effect=(error, '', 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)):
+    with mock.patch('os.path.getsize', return_value=1337):
       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'])
+      self.assertEquals(3, len(device.RunShellCommand.call_args_list))
       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'])
+          'test/out/directory/md5sum_dist', '/data/local/tmp/md5sum')
 
 
 if __name__ == '__main__':
diff --git a/build/android/pylib/uiautomator/__init__.py b/build/android/devil/android/perf/__init__.py
similarity index 61%
copy from build/android/pylib/uiautomator/__init__.py
copy to build/android/devil/android/perf/__init__.py
index cda7672..50b23df 100644
--- a/build/android/pylib/uiautomator/__init__.py
+++ b/build/android/devil/android/perf/__init__.py
@@ -1,4 +1,3 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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/devil/android/perf/cache_control.py b/build/android/devil/android/perf/cache_control.py
new file mode 100644
index 0000000..7bd0a4e
--- /dev/null
+++ b/build/android/devil/android/perf/cache_control.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.
+
+
+class CacheControl(object):
+  _DROP_CACHES = '/proc/sys/vm/drop_caches'
+
+  def __init__(self, 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/devil/android/perf/perf_control.py b/build/android/devil/android/perf/perf_control.py
new file mode 100644
index 0000000..af1d52c
--- /dev/null
+++ b/build/android/devil/android/perf/perf_control.py
@@ -0,0 +1,156 @@
+# Copyright 2013 The Chromium 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 devil.android import device_errors
+
+
+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):
+    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."""
+    try:
+      self._device.EnableRoot()
+    except device_errors.CommandFailedError:
+      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', path, value)
+
+  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/devil/android/perf/perf_control_unittest.py
similarity index 86%
rename from build/android/pylib/perf/perf_control_unittest.py
rename to build/android/devil/android/perf/perf_control_unittest.py
index 69b8b46..90907bd 100644
--- a/build/android/pylib/perf/perf_control_unittest.py
+++ b/build/android/devil/android/perf/perf_control_unittest.py
@@ -9,15 +9,15 @@
 
 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
+from devil.android import device_utils
+from devil.android.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()
+    devices = device_utils.DeviceUtils.HealthyDevices(blacklist=None)
     self.assertGreater(len(devices), 0, 'No device attached!')
     self._device = devices[0]
 
diff --git a/build/android/devil/android/perf/surface_stats_collector.py b/build/android/devil/android/perf/surface_stats_collector.py
new file mode 100644
index 0000000..49372ad
--- /dev/null
+++ b/build/android/devil/android/perf/surface_stats_collector.py
@@ -0,0 +1,183 @@
+# Copyright 2013 The Chromium 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 threading
+
+
+# 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):
+    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/devil/android/perf/thermal_throttle.py b/build/android/devil/android/perf/thermal_throttle.py
new file mode 100644
index 0000000..9aad4bb
--- /dev/null
+++ b/build/android/devil/android/perf/thermal_throttle.py
@@ -0,0 +1,132 @@
+# Copyright 2013 The Chromium 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
+
+
+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):
+    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/ports.py b/build/android/devil/android/ports.py
similarity index 81%
rename from build/android/pylib/ports.py
rename to build/android/devil/android/ports.py
index 578152c..eff30ce 100644
--- a/build/android/pylib/ports.py
+++ b/build/android/devil/android/ports.py
@@ -12,7 +12,12 @@
 import socket
 import traceback
 
-from pylib import constants
+# The net test server is started from port 10201.
+_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'
 
 
 # The following two methods are used to allocate the port source for various
@@ -27,13 +32,13 @@
     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)
+    with open(_TEST_SERVER_PORT_FILE, 'w') as fp:
+      fp.write('%d' % _TEST_SERVER_PORT_FIRST)
+    if os.path.exists(_TEST_SERVER_PORT_LOCKFILE):
+      os.unlink(_TEST_SERVER_PORT_LOCKFILE)
     return True
-  except Exception as e:
-    logging.error(e)
+  except Exception: # pylint: disable=broad-except
+    logging.exception('Error while resetting port allocation')
   return False
 
 
@@ -47,25 +52,25 @@
   port = 0
   ports_tried = []
   try:
-    fp_lock = open(constants.TEST_SERVER_PORT_LOCKFILE, 'w')
+    fp_lock = open(_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):
+    if not os.path.exists(_TEST_SERVER_PORT_FILE):
       ResetTestServerPortAllocation()
-    with open(constants.TEST_SERVER_PORT_FILE, 'r+') as fp:
+    with open(_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):
+      if (port > _TEST_SERVER_PORT_LAST or
+          port < _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)
+  except Exception: # pylint: disable=broad-except
+    logging.exception('ERror while allocating port')
   finally:
     if fp_lock:
       fcntl.flock(fp_lock, fcntl.LOCK_UN)
@@ -109,8 +114,9 @@
   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')
+  base_urls = ('127.0.0.1:%d' % device_port, 'localhost:%d' % device_port)
+  netstat_results = device.RunShellCommand(
+      ['netstat', '-a'], check_return=True, large_output=True)
   for single_connect in netstat_results:
     # Column 3 is the local address which we want to check with.
     connect_results = single_connect.split()
@@ -120,7 +126,7 @@
       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:
+    if connect_results[3] in base_urls and is_state_match:
       return True
   return False
 
diff --git a/build/android/devil/android/sdk/__init__.py b/build/android/devil/android/sdk/__init__.py
new file mode 100644
index 0000000..f95d3b2
--- /dev/null
+++ b/build/android/devil/android/sdk/__init__.py
@@ -0,0 +1,6 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This package is intended for modules that are very tightly coupled to
+# tools or APIs from the Android SDK.
diff --git a/build/android/devil/android/sdk/aapt.py b/build/android/devil/android/sdk/aapt.py
new file mode 100644
index 0000000..1c051e0
--- /dev/null
+++ b/build/android/devil/android/sdk/aapt.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.
+
+"""This module wraps the Android Asset Packaging Tool."""
+
+import os
+
+from devil.utils import cmd_helper
+from pylib import constants
+
+_AAPT_PATH = os.path.join(constants.ANDROID_SDK_TOOLS, 'aapt')
+
+def _RunAaptCmd(args):
+  """Runs an aapt command.
+
+  Args:
+    args: A list of arguments for aapt.
+
+  Returns:
+    The output of the command.
+  """
+  cmd = [_AAPT_PATH] + args
+  status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
+  if status != 0:
+    raise Exception('Failed running aapt command: "%s" with output "%s".' %
+                    (' '.join(cmd), output))
+  return output
+
+def Dump(what, apk, assets=None):
+  """Returns the output of the aapt dump command.
+
+  Args:
+    what: What you want to dump.
+    apk: Path to apk you want to dump information for.
+    assets: List of assets in apk you want to dump information for.
+  """
+  assets = assets or []
+  if isinstance(assets, basestring):
+    assets = [assets]
+  return _RunAaptCmd(['dump', what, apk] + assets).splitlines()
diff --git a/build/android/devil/android/sdk/adb_wrapper.py b/build/android/devil/android/sdk/adb_wrapper.py
new file mode 100644
index 0000000..5a81c7f
--- /dev/null
+++ b/build/android/devil/android/sdk/adb_wrapper.py
@@ -0,0 +1,664 @@
+# Copyright 2013 The Chromium Authors. 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 devil.android import decorators
+from devil.android import device_errors
+from devil.utils import cmd_helper
+from devil.utils import timeout_retry
+from pylib import constants
+
+
+_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):
+    # pylint: disable=no-member
+    status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
+        cls._BuildAdbCmd(args, device_serial, cpu_affinity=cpu_affinity),
+        timeout_retry.CurrentTimeoutThreadGroup().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, desired_state=_READY_STATE, long_list=False,
+              timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """Get the list of active attached devices.
+
+    Args:
+      desired_state: If not None, limit the devices returned to only those
+        in the given state.
+      long_list: Whether to use the long listing format.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+
+    Yields:
+      AdbWrapper instances.
+    """
+    lines = cls._RawDevices(long_list=long_list, timeout=timeout,
+                            retries=retries)
+    if long_list:
+      return [
+        [AdbWrapper(line[0])] + line[1:]
+        for line in lines
+        if (len(line) >= 2 and (not desired_state or line[1] == desired_state))
+      ]
+    else:
+      return [
+        AdbWrapper(line[0])
+        for line in lines
+        if (len(line) == 2 and (not desired_state or line[1] == desired_state))
+      ]
+
+  @classmethod
+  def _RawDevices(cls, long_list=False, timeout=_DEFAULT_TIMEOUT,
+                  retries=_DEFAULT_RETRIES):
+    cmd = ['devices']
+    if long_list:
+      cmd.append('-l')
+    output = cls._RunAdbCmd(cmd, timeout=timeout, retries=retries)
+    return [line.split() for line in output.splitlines()[1:]]
+
+  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, or the output of "adb ls" command is less
+          than four columns
+    """
+    def ParseLine(line, cmd):
+      cols = line.split(None, 3)
+      if len(cols) < 4:
+        raise device_errors.AdbCommandFailedError(
+            cmd, line, "the output should be 4 columns, but is only %d columns"
+            % len(cols), device_serial=self._device_serial)
+      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, cmd) 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 ForwardRemove(self, local, timeout=_DEFAULT_TIMEOUT,
+                    retries=_DEFAULT_RETRIES):
+    """Remove a forward socket connection.
+
+    Args:
+      local: The host socket.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    self._RunDeviceAdbCmd(['forward', '--remove', str(local)], timeout,
+                          retries)
+
+  def ForwardList(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """List all currently forwarded socket connections.
+
+    Args:
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    return self._RunDeviceAdbCmd(['forward', '--list'], 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 InstallMultiple(self, apk_paths, forward_lock=False, reinstall=False,
+                      sd_card=False, allow_downgrade=False, partial=False,
+                      timeout=60*2, retries=_DEFAULT_RETRIES):
+    """Install an apk with splits on the device.
+
+    Args:
+      apk_paths: 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.
+      allow_downgrade: (optional) Allow versionCode downgrade.
+      partial: (optional) Package ID if apk_paths doesn't include all .apks.
+    """
+    for path in apk_paths:
+      _VerifyLocalFileExists(path)
+    cmd = ['install-multiple']
+    if forward_lock:
+      cmd.append('-l')
+    if reinstall:
+      cmd.append('-r')
+    if sd_card:
+      cmd.append('-s')
+    if allow_downgrade:
+      cmd.append('-d')
+    if partial:
+      cmd.extend(('-p', partial))
+    cmd.extend(apk_paths)
+    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'.
+    """
+    # TODO(jbudorick): Revert to using get-state once it doesn't cause a
+    # a protocol fault.
+    # return self._RunDeviceAdbCmd(['get-state'], timeout, retries).strip()
+
+    lines = self._RawDevices(timeout=timeout, retries=retries)
+    for line in lines:
+      if len(line) >= 2 and line[0] == self._device_serial:
+        return line[1]
+    return 'offline'
+
+
+  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/devil/android/sdk/adb_wrapper_test.py
similarity index 96%
rename from build/android/pylib/device/adb_wrapper_test.py
rename to build/android/devil/android/sdk/adb_wrapper_test.py
index 5fc9eb6..7c098a9 100644
--- a/build/android/pylib/device/adb_wrapper_test.py
+++ b/build/android/devil/android/sdk/adb_wrapper_test.py
@@ -9,8 +9,8 @@
 import time
 import unittest
 
-from pylib.device import adb_wrapper
-from pylib.device import device_errors
+from devil.android import device_errors
+from devil.android.sdk import adb_wrapper
 
 
 class TestAdbWrapper(unittest.TestCase):
diff --git a/build/android/devil/android/sdk/dexdump.py b/build/android/devil/android/sdk/dexdump.py
new file mode 100644
index 0000000..48d810f
--- /dev/null
+++ b/build/android/devil/android/sdk/dexdump.py
@@ -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.
+
+import os
+
+from devil.utils import cmd_helper
+from pylib import constants
+
+_DEXDUMP_PATH = os.path.join(constants.ANDROID_SDK_TOOLS, 'dexdump')
+
+def DexDump(dexfiles, file_summary=False):
+  """A wrapper around the Android SDK's dexdump tool.
+
+  Args:
+    dexfiles: The dexfile or list of dex files to dump.
+    file_summary: Display summary information from the file header. (-f)
+
+  Returns:
+    An iterable over the output lines.
+  """
+  # TODO(jbudorick): Add support for more options as necessary.
+  if isinstance(dexfiles, basestring):
+    dexfiles = [dexfiles]
+  args = [_DEXDUMP_PATH] + dexfiles
+  if file_summary:
+    args.append('-f')
+
+  return cmd_helper.IterCmdOutputLines(args)
+
diff --git a/build/android/devil/android/sdk/fastboot.py b/build/android/devil/android/sdk/fastboot.py
new file mode 100644
index 0000000..cfc566a
--- /dev/null
+++ b/build/android/devil/android/sdk/fastboot.py
@@ -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.
+
+"""This module wraps Android's fastboot tool.
+
+This is a thin wrapper around the fastboot interface. Any additional complexity
+should be delegated to a higher level (ex. FastbootUtils).
+"""
+# pylint: disable=unused-argument
+
+import os
+
+from devil.android import decorators
+from devil.android import device_errors
+from devil.utils import cmd_helper
+from pylib import constants
+
+_FASTBOOT_CMD = os.path.join(
+    constants.ANDROID_SDK_ROOT, 'platform-tools', 'fastboot')
+_DEFAULT_TIMEOUT = 30
+_DEFAULT_RETRIES = 3
+_FLASH_TIMEOUT = _DEFAULT_TIMEOUT * 10
+
+class Fastboot(object):
+
+  def __init__(self, device_serial, default_timeout=_DEFAULT_TIMEOUT,
+               default_retries=_DEFAULT_RETRIES):
+    """Initializes the FastbootWrapper.
+
+    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)
+    self._default_timeout = default_timeout
+    self._default_retries = default_retries
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def _RunFastbootCommand(self, cmd, timeout=None, retries=None):
+    """Run a command line command using the fastboot android tool.
+
+    Args:
+      cmd: Command to run. Must be list of args, the first one being the command
+
+    Returns:
+      output of command.
+
+    Raises:
+      TypeError: If cmd is not of type list.
+    """
+    if type(cmd) == list:
+      cmd = [_FASTBOOT_CMD, '-s', self._device_serial] + cmd
+    else:
+      raise TypeError(
+          'Command for _RunFastbootCommand must be a list.')
+    status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
+    if int(status) != 0:
+      raise device_errors.FastbootCommandFailedError(
+          cmd, output, status, self._device_serial)
+    return output
+
+  @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0)
+  def Flash(self, partition, image, timeout=None, retries=None):
+    """Flash partition with img.
+
+    Args:
+      partition: Partition to be flashed.
+      image: location of image to flash with.
+    """
+    self._RunFastbootCommand(['flash', partition, image])
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def Devices(self, timeout=None, retries=None):
+    """Outputs list of devices in fastboot mode."""
+    output = self._RunFastbootCommand(['devices'])
+    return [line.split()[0] for line in output.splitlines()]
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def RebootBootloader(self, timeout=None, retries=None):
+    """Reboot from fastboot, into fastboot."""
+    self._RunFastbootCommand(['reboot-bootloader'])
+
+  @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0)
+  def Reboot(self, timeout=None, retries=None):
+    """Reboot from fastboot to normal usage"""
+    self._RunFastbootCommand(['reboot'])
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def SetOemOffModeCharge(self, value, timeout=None, retries=None):
+    """Sets off mode charging
+
+    Args:
+      value: boolean value to set off-mode-charging on or off.
+    """
+    self._RunFastbootCommand(
+        ['oem', 'off-mode-charge', str(int(value))])
diff --git a/build/android/devil/android/sdk/intent.py b/build/android/devil/android/sdk/intent.py
new file mode 100644
index 0000000..333b9f1
--- /dev/null
+++ b/build/android/devil/android/sdk/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/constants/keyevent.py b/build/android/devil/android/sdk/keyevent.py
similarity index 100%
rename from build/android/pylib/constants/keyevent.py
rename to build/android/devil/android/sdk/keyevent.py
diff --git a/build/android/devil/android/sdk/shared_prefs.py b/build/android/devil/android/sdk/shared_prefs.py
new file mode 100644
index 0000000..2b430d5
--- /dev/null
+++ b/build/android/devil/android/sdk/shared_prefs.py
@@ -0,0 +1,390 @@
+# Copyright 2015 The Chromium 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 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, exact=True, 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/devil/android/sdk/shared_prefs_test.py
similarity index 95%
rename from build/android/pylib/device/shared_prefs_test.py
rename to build/android/devil/android/sdk/shared_prefs_test.py
index c5f0ec3..63d9aec 100755
--- a/build/android/pylib/device/shared_prefs_test.py
+++ b/build/android/devil/android/sdk/shared_prefs_test.py
@@ -12,13 +12,13 @@
 import sys
 import unittest
 
+from devil.android import device_utils
+from devil.android.sdk import shared_prefs
 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
+import mock # pylint: disable=import-error
 
 
 def MockDeviceWithFiles(files=None):
@@ -113,8 +113,8 @@
     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.device.KillAll.assert_called_once_with(prefs.package, exact=True,
+                                                as_root=True, quiet=True)
     self.assertFalse(prefs.changed)
 
     prefs = shared_prefs.SharedPrefs(
diff --git a/build/android/devil/android/sdk/split_select.py b/build/android/devil/android/sdk/split_select.py
new file mode 100644
index 0000000..47fcea3
--- /dev/null
+++ b/build/android/devil/android/sdk/split_select.py
@@ -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.
+
+"""This module wraps Android's split-select tool."""
+
+import os
+
+from devil.utils import cmd_helper
+from pylib import constants
+
+_SPLIT_SELECT_PATH = os.path.join(constants.ANDROID_SDK_TOOLS, 'split-select')
+
+def _RunSplitSelectCmd(args):
+  """Runs a split-select command.
+
+  Args:
+    args: A list of arguments for split-select.
+
+  Returns:
+    The output of the command.
+  """
+  cmd = [_SPLIT_SELECT_PATH] + args
+  status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
+  if status != 0:
+    raise Exception('Failed running command "%s" with output "%s".' %
+                    (' '.join(cmd), output))
+  return output
+
+def _SplitConfig(device, allow_cached_props=False):
+  """Returns a config specifying which APK splits are required by the device.
+
+  Args:
+    device: A DeviceUtils object.
+    allow_cached_props: Whether to use cached values for device properties.
+  """
+  return ('%s-r%s-%s:%s' %
+          (device.GetLanguage(cache=allow_cached_props),
+           device.GetCountry(cache=allow_cached_props),
+           device.screen_density,
+           device.product_cpu_abi))
+
+def SelectSplits(device, base_apk, split_apks, allow_cached_props=False):
+  """Determines which APK splits the device requires.
+
+  Args:
+    device: A DeviceUtils object.
+    base_apk: The path of the base APK.
+    split_apks: A list of paths of APK splits.
+    allow_cached_props: Whether to use cached values for device properties.
+
+  Returns:
+    The list of APK splits that the device requires.
+  """
+  config = _SplitConfig(device, allow_cached_props=allow_cached_props)
+  args = ['--target', config, '--base', base_apk]
+  for split in split_apks:
+    args.extend(['--split', split])
+  return _RunSplitSelectCmd(args).splitlines()
diff --git a/build/android/devil/android/sdk/version_codes.py b/build/android/devil/android/sdk/version_codes.py
new file mode 100644
index 0000000..410379b
--- /dev/null
+++ b/build/android/devil/android/sdk/version_codes.py
@@ -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.
+
+"""Android SDK version codes.
+
+http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
+"""
+
+JELLY_BEAN = 16
+JELLY_BEAN_MR1 = 17
+JELLY_BEAN_MR2 = 18
+KITKAT = 19
+KITKAT_WATCH = 20
+LOLLIPOP = 21
+LOLLIPOP_MR1 = 22
+MARSHMALLOW = 23
+
diff --git a/build/android/devil/android/tools/flash_device.py b/build/android/devil/android/tools/flash_device.py
new file mode 100755
index 0000000..a56a349
--- /dev/null
+++ b/build/android/devil/android/tools/flash_device.py
@@ -0,0 +1,81 @@
+#!/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 argparse
+import logging
+import sys
+
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.android import fastboot_utils
+from devil.android.sdk import adb_wrapper
+from devil.constants import exit_codes
+from devil.utils import run_tests_helper
+
+
+def GetDeviceList(device=None):
+  """Returns a list of devices.
+
+  If device is passed to it, returns only that device.
+  """
+  available_devices = [device_utils.DeviceUtils(d)
+                       for d in adb_wrapper.AdbWrapper.GetDevices()]
+  if not available_devices:
+    raise device_errors.NoDevicesError
+  if not device:
+    return available_devices
+  for d in available_devices:
+    if str(d) == device:
+      return [d]
+  raise device_errors.NoDevicesError
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('build_path', help='Path to android build.')
+  parser.add_argument('-d', '--device', help='Device to flash.')
+  parser.add_argument('-v', '--verbose', default=0, action='count',
+                      help='Verbose level (multiple times for more)')
+  parser.add_argument('-w', '--wipe', action='store_true',
+                       help='If set, wipes user data')
+  parser.add_argument('--blacklist-file', help='Device blacklist file.')
+  args = parser.parse_args()
+  run_tests_helper.SetLogLevel(args.verbose)
+
+  if args.blacklist_file:
+    blacklist = device_blacklist.Blacklist(args.blacklist_file).Read()
+    if blacklist:
+      logging.critical('Device(s) in blacklist, not flashing devices:')
+      for key in blacklist:
+        logging.critical('  %s', key)
+      return exit_codes.INFRA
+
+  flashed_devices = []
+  failed_devices = []
+
+  def flash(device):
+    fastboot = fastboot_utils.FastbootUtils(device)
+    try:
+      fastboot.FlashDevice(args.build_path, wipe=args.wipe)
+      flashed_devices.append(device)
+    except Exception: # pylint: disable=broad-except
+      logging.exception('Device %s failed to flash.', str(device))
+      failed_devices.append(device)
+
+  devices = GetDeviceList(device=args.device)
+  device_utils.DeviceUtils.parallel(devices).pMap(flash)
+
+  if flashed_devices:
+    logging.info('The following devices were flashed:')
+    logging.info('  %s', ' '.join(str(d) for d in flashed_devices))
+  if failed_devices:
+    logging.critical('The following devices failed to flash:')
+    logging.critical('  %s', ' '.join(str(d) for d in failed_devices))
+    return exit_codes.INFRA
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/devil/android/valgrind_tools/__init__.py b/build/android/devil/android/valgrind_tools/__init__.py
new file mode 100644
index 0000000..0182d4c
--- /dev/null
+++ b/build/android/devil/android/valgrind_tools/__init__.py
@@ -0,0 +1,21 @@
+# 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.
+"""
+Classes in this package 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().
+"""
diff --git a/build/android/devil/android/valgrind_tools/base_tool.py b/build/android/devil/android/valgrind_tools/base_tool.py
new file mode 100644
index 0000000..2e6e9af
--- /dev/null
+++ b/build/android/devil/android/valgrind_tools/base_tool.py
@@ -0,0 +1,53 @@
+# 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.
+
+
+class BaseTool(object):
+  """A tool that does nothing."""
+  # pylint: disable=R0201
+
+  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
diff --git a/build/android/devil/base_error.py b/build/android/devil/base_error.py
new file mode 100644
index 0000000..dadf4da
--- /dev/null
+++ b/build/android/devil/base_error.py
@@ -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.
+
+
+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
+
diff --git a/build/android/pylib/uiautomator/__init__.py b/build/android/devil/constants/__init__.py
similarity index 61%
copy from build/android/pylib/uiautomator/__init__.py
copy to build/android/devil/constants/__init__.py
index cda7672..50b23df 100644
--- a/build/android/pylib/uiautomator/__init__.py
+++ b/build/android/devil/constants/__init__.py
@@ -1,4 +1,3 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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/devil/constants/exit_codes.py b/build/android/devil/constants/exit_codes.py
new file mode 100644
index 0000000..aaeca4a
--- /dev/null
+++ b/build/android/devil/constants/exit_codes.py
@@ -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.
+
+"""Common exit codes used by devil."""
+
+ERROR = 1
+INFRA = 87
+WARNING = 88
diff --git a/build/android/pylib/uiautomator/__init__.py b/build/android/devil/utils/__init__.py
similarity index 61%
copy from build/android/pylib/uiautomator/__init__.py
copy to build/android/devil/utils/__init__.py
index cda7672..50b23df 100644
--- a/build/android/pylib/uiautomator/__init__.py
+++ b/build/android/devil/utils/__init__.py
@@ -1,4 +1,3 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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/devil/utils/cmd_helper.py b/build/android/devil/utils/cmd_helper.py
new file mode 100644
index 0000000..57e8987
--- /dev/null
+++ b/build/android/devil/utils/cmd_helper.py
@@ -0,0 +1,311 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""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 ShrinkToSnippet(cmd_parts, var_name, var_value):
+  """Constructs a shell snippet for a command using a variable to shrink it.
+
+  Takes into account all quoting that needs to happen.
+
+  Args:
+    cmd_parts: A list of command arguments.
+    var_name: The variable that holds var_value.
+    var_value: The string to replace in cmd_parts with $var_name
+
+  Returns:
+    A shell snippet that does not include setting the variable.
+  """
+  def shrink(value):
+    parts = (x and SingleQuote(x) for x in value.split(var_value))
+    with_substitutions = ('"$%s"' % var_name).join(parts)
+    return with_substitutions or "''"
+
+  return ' '.join(shrink(part) for part in cmd_parts)
+
+
+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).
+  """
+  status, stdout, stderr = GetCmdStatusOutputAndError(
+      args, cwd=cwd, shell=shell)
+
+  if stderr:
+    logging.critical(stderr)
+  if len(stdout) > 4096:
+    logging.debug('Truncated output:')
+  logging.debug(stdout[:4096])
+  return (status, stdout)
+
+def GetCmdStatusOutputAndError(args, cwd=None, shell=False):
+  """Executes a subprocess and returns its exit code, output, and errors.
+
+  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()
+  return (pipe.returncode, stdout, stderr)
+
+
+class TimeoutError(Exception):
+  """Module-specific timeout exception."""
+
+  def __init__(self, output=None):
+    super(TimeoutError, self).__init__()
+    self._output = output
+
+  @property
+  def output(self):
+    return self._output
+
+
+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)
+  try:
+    for data in _IterProcessStdout(process, timeout=timeout):
+      if logfile:
+        logfile.write(data)
+      output.write(data)
+  except TimeoutError:
+    raise TimeoutError(output.getvalue())
+
+  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/devil/utils/cmd_helper_test.py
old mode 100644
new mode 100755
similarity index 67%
rename from build/android/pylib/cmd_helper_test.py
rename to build/android/devil/utils/cmd_helper_test.py
index 5155cea..c01c319
--- a/build/android/pylib/cmd_helper_test.py
+++ b/build/android/devil/utils/cmd_helper_test.py
@@ -1,3 +1,4 @@
+#!/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.
@@ -7,7 +8,7 @@
 import unittest
 import subprocess
 
-from pylib import cmd_helper
+from devil.utils import cmd_helper
 
 
 class CmdHelperSingleQuoteTest(unittest.TestCase):
@@ -52,6 +53,36 @@
                       cmd_helper.GetCmdOutput(cmd, shell=True).rstrip())
 
 
+class CmdHelperShinkToSnippetTest(unittest.TestCase):
+
+  def testShrinkToSnippet_noArgs(self):
+    self.assertEquals('foo',
+        cmd_helper.ShrinkToSnippet(['foo'], 'a', 'bar'))
+    self.assertEquals("'foo foo'",
+        cmd_helper.ShrinkToSnippet(['foo foo'], 'a', 'bar'))
+    self.assertEquals('"$a"\' bar\'',
+        cmd_helper.ShrinkToSnippet(['foo bar'], 'a', 'foo'))
+    self.assertEquals('\'foo \'"$a"',
+        cmd_helper.ShrinkToSnippet(['foo bar'], 'a', 'bar'))
+    self.assertEquals('foo"$a"',
+        cmd_helper.ShrinkToSnippet(['foobar'], 'a', 'bar'))
+
+  def testShrinkToSnippet_singleArg(self):
+    self.assertEquals("foo ''",
+        cmd_helper.ShrinkToSnippet(['foo', ''], 'a', 'bar'))
+    self.assertEquals("foo foo",
+        cmd_helper.ShrinkToSnippet(['foo', 'foo'], 'a', 'bar'))
+    self.assertEquals('"$a" "$a"',
+        cmd_helper.ShrinkToSnippet(['foo', 'foo'], 'a', 'foo'))
+    self.assertEquals('foo "$a""$a"',
+        cmd_helper.ShrinkToSnippet(['foo', 'barbar'], 'a', 'bar'))
+    self.assertEquals('foo "$a"\' \'"$a"',
+        cmd_helper.ShrinkToSnippet(['foo', 'bar bar'], 'a', 'bar'))
+    self.assertEquals('foo "$a""$a"\' \'',
+        cmd_helper.ShrinkToSnippet(['foo', 'barbar '], 'a', 'bar'))
+    self.assertEquals('foo \' \'"$a""$a"\' \'',
+        cmd_helper.ShrinkToSnippet(['foo', ' barbar '], 'a', 'bar'))
+
 class CmdHelperIterCmdOutputLinesTest(unittest.TestCase):
   """Test IterCmdOutputLines with some calls to the unix 'seq' command."""
 
@@ -81,3 +112,7 @@
       # the end of the output and, thus, the status never gets checked
       if num == 10:
         break
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/devil/utils/host_utils.py b/build/android/devil/utils/host_utils.py
new file mode 100644
index 0000000..580721f
--- /dev/null
+++ b/build/android/devil/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/devil/utils/lsusb.py b/build/android/devil/utils/lsusb.py
new file mode 100644
index 0000000..9c98fa6
--- /dev/null
+++ b/build/android/devil/utils/lsusb.py
@@ -0,0 +1,87 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import re
+
+from pylib import cmd_helper
+
+_INDENTATION_RE = re.compile(r'^( *)')
+_LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}):')
+_LSUSB_ENTRY_RE = re.compile(r'^ *([^ ]+) +([^ ]+) *([^ ].*)?$')
+_LSUSB_GROUP_RE = re.compile(r'^ *([^ ]+.*):$')
+
+_USBDEVFS_RESET = ord('U') << 8 | 20
+
+
+def lsusb():
+  """Call lsusb and return the parsed output."""
+  lsusb_raw_output = cmd_helper.GetCmdOutput(['lsusb', '-v'])
+  device = None
+  devices = []
+  depth_stack = []
+  for line in lsusb_raw_output.splitlines():
+    if not line:
+      if device:
+        devices.append(device)
+      device = None
+      continue
+
+    if not device:
+      m = _LSUSB_BUS_DEVICE_RE.match(line)
+      if m:
+        device = {
+          'bus': m.group(1),
+          'device': m.group(2)
+        }
+        depth_stack = [device]
+      continue
+
+    indent_match = _INDENTATION_RE.match(line)
+    if not indent_match:
+      continue
+
+    depth = 1 + len(indent_match.group(1)) / 2
+    if depth > len(depth_stack):
+      logging.error('lsusb parsing error: unexpected indentation: "%s"', line)
+      continue
+
+    while depth < len(depth_stack):
+      depth_stack.pop()
+
+    cur = depth_stack[-1]
+
+    m = _LSUSB_GROUP_RE.match(line)
+    if m:
+      new_group = {}
+      cur[m.group(1)] = new_group
+      depth_stack.append(new_group)
+      continue
+
+    m = _LSUSB_ENTRY_RE.match(line)
+    if m:
+      new_entry = {
+        '_value': m.group(2),
+        '_desc': m.group(3),
+      }
+      cur[m.group(1)] = new_entry
+      depth_stack.append(new_entry)
+      continue
+
+    logging.error('lsusb parsing error: unrecognized line: "%s"', line)
+
+  if device:
+    devices.append(device)
+
+  return devices
+
+
+def get_lsusb_serial(device):
+  return device.get('Device Descriptor', {}).get('iSerial', {}).get('_desc')
+
+
+def get_android_devices():
+  return [serial for serial in (get_lsusb_serial(d) for d in lsusb())
+          if serial]
+
diff --git a/build/android/devil/utils/mock_calls.py b/build/android/devil/utils/mock_calls.py
new file mode 100644
index 0000000..59167ba
--- /dev/null
+++ b/build/android/devil/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/devil/utils/mock_calls_test.py
similarity index 90%
rename from build/android/pylib/utils/mock_calls_test.py
rename to build/android/devil/utils/mock_calls_test.py
index 4dbafd4..ae2acbb 100755
--- a/build/android/pylib/utils/mock_calls_test.py
+++ b/build/android/devil/utils/mock_calls_test.py
@@ -12,8 +12,9 @@
 import sys
 import unittest
 
+from devil.android.sdk import version_codes
+from devil.utils import mock_calls
 from pylib import constants
-from pylib.utils import mock_calls
 
 sys.path.append(os.path.join(
     constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
@@ -41,7 +42,7 @@
   @property
   def build_version_sdk(self):
     logging.debug('(device %s) getting build_version_sdk', self)
-    return constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP
+    return version_codes.LOLLIPOP
 
 
 class TestCaseWithAssertCallsTest(mock_calls.TestCase):
@@ -97,15 +98,12 @@
         self.adb.Shell('echo hello')
 
   def testPatchCall_property(self):
-    self.assertEquals(constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP,
-                      self.adb.build_version_sdk)
+    self.assertEquals(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)
+        return_value=version_codes.KITKAT):
+      self.assertEquals(version_codes.KITKAT, self.adb.build_version_sdk)
+    self.assertEquals(version_codes.LOLLIPOP, self.adb.build_version_sdk)
 
   def testAssertCalls_succeeds_simple(self):
     self.assertEquals(42, self.get_answer())
diff --git a/build/android/devil/utils/parallelizer.py b/build/android/devil/utils/parallelizer.py
new file mode 100644
index 0000000..bac5b24
--- /dev/null
+++ b/build/android/devil/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 devil.utils import reraiser_thread
+from devil.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/devil/utils/parallelizer_test.py
similarity index 98%
rename from build/android/pylib/utils/parallelizer_test.py
rename to build/android/devil/utils/parallelizer_test.py
index 6e0c7e7..0589a04 100644
--- a/build/android/pylib/utils/parallelizer_test.py
+++ b/build/android/devil/utils/parallelizer_test.py
@@ -12,7 +12,7 @@
 import time
 import unittest
 
-from pylib.utils import parallelizer
+from devil.utils import parallelizer
 
 
 class ParallelizerTestObject(object):
diff --git a/build/android/devil/utils/reraiser_thread.py b/build/android/devil/utils/reraiser_thread.py
new file mode 100644
index 0000000..e108fc7
--- /dev/null
+++ b/build/android/devil/utils/reraiser_thread.py
@@ -0,0 +1,228 @@
+# Copyright 2013 The Chromium 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 time
+import traceback
+
+from devil.utils import watchdog_timer
+
+
+class TimeoutError(Exception):
+  """Module-specific timeout exception."""
+  pass
+
+
+def LogThreadStack(thread, error_log_func=logging.critical):
+  """Log the stack for the given thread.
+
+  Args:
+    thread: a threading.Thread instance.
+    error_log_func: Logging function when logging errors.
+  """
+  stack = sys._current_frames()[thread.ident]
+  error_log_func('*' * 80)
+  error_log_func('Stack dump for thread %r', thread.name)
+  error_log_func('*' * 80)
+  for filename, lineno, name, line in traceback.extract_stack(stack):
+    error_log_func('File: "%s", line %d, in %s', filename, lineno, name)
+    if line:
+      error_log_func('  %s', line.strip())
+  error_log_func('*' * 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.
+    """
+    if not name and func.__name__ != '<lambda>':
+      name = func.__name__
+    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
+    self._thread_group = 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.
+    """
+    self._threads = []
+    # Set when a thread from one group has called JoinAll on another. It is used
+    # to detect when a there is a TimeoutRetryThread active that links to the
+    # current thread.
+    self.blocked_parent_thread_group = None
+    if threads:
+      for thread in threads:
+        self.Add(thread)
+
+  def Add(self, thread):
+    """Add a thread to the group.
+
+    Args:
+      thread: a ReraiserThread object.
+    """
+    assert thread._thread_group is None
+    thread._thread_group = self
+    self._threads.append(thread)
+
+  def StartAll(self, will_block=False):
+    """Start all threads.
+
+    Args:
+      will_block: Whether the calling thread will subsequently block on this
+        thread group. Causes the active ReraiserThreadGroup (if there is one)
+        to be marked as blocking on this thread group.
+    """
+    if will_block:
+      # Multiple threads blocking on the same outer thread should not happen in
+      # practice.
+      assert not self.blocked_parent_thread_group
+      self.blocked_parent_thread_group = CurrentThreadGroup()
+    for thread in self._threads:
+      thread.start()
+
+  def _JoinAll(self, watcher=None, timeout=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 the thread timeout. If none is
+          provided, the thread will never be timed out.
+      timeout: An optional number of seconds to wait before timing out the join
+          operation. This will not time out the threads.
+    """
+    if watcher is None:
+      watcher = watchdog_timer.WatchdogTimer(None)
+    alive_threads = self._threads[:]
+    end_time = (time.time() + timeout) if timeout else None
+    try:
+      while alive_threads and (end_time is None or end_time > time.time()):
+        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()
+    finally:
+      self.blocked_parent_thread_group = None
+
+  def IsAlive(self):
+    """Check whether any of the threads are still alive.
+
+    Returns:
+      Whether any of the threads are still alive.
+    """
+    return any(t.isAlive() for t in self._threads)
+
+  def JoinAll(self, watcher=None, timeout=None,
+              error_log_func=logging.critical):
+    """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 the thread timeout. If none is
+          provided, the thread will never be timed out.
+      timeout: An optional number of seconds to wait before timing out the join
+          operation. This will not time out the threads.
+      error_log_func: Logging function when logging errors.
+    """
+    try:
+      self._JoinAll(watcher, timeout)
+    except TimeoutError:
+      error_log_func('Timed out. Dumping threads.')
+      for thread in (t for t in self._threads if t.isAlive()):
+        LogThreadStack(thread, error_log_func=error_log_func)
+      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]
+
+
+def CurrentThreadGroup():
+  """Returns the ReraiserThreadGroup that owns the running thread.
+
+  Returns:
+    The current thread group, otherwise None.
+  """
+  current_thread = threading.current_thread()
+  if isinstance(current_thread, ReraiserThread):
+    return current_thread._thread_group  # pylint: disable=no-member
+  return None
+
+
+def RunAsync(funcs, watcher=None):
+  """Executes the given functions in parallel and returns their results.
+
+  Args:
+    funcs: List of functions to perform on their own threads.
+    watcher: Watchdog object providing timeout, by default waits forever.
+
+  Returns:
+    A list of return values in the order of the given functions.
+  """
+  thread_group = ReraiserThreadGroup(ReraiserThread(f) for f in funcs)
+  thread_group.StartAll(will_block=True)
+  return thread_group.GetAllReturnValues(watcher=watcher)
diff --git a/build/android/pylib/utils/reraiser_thread_unittest.py b/build/android/devil/utils/reraiser_thread_unittest.py
similarity index 81%
rename from build/android/pylib/utils/reraiser_thread_unittest.py
rename to build/android/devil/utils/reraiser_thread_unittest.py
index 2392d0e..dcd243b 100644
--- a/build/android/pylib/utils/reraiser_thread_unittest.py
+++ b/build/android/devil/utils/reraiser_thread_unittest.py
@@ -7,8 +7,8 @@
 import threading
 import unittest
 
-from pylib.utils import reraiser_thread
-from pylib.utils import watchdog_timer
+from devil.utils import reraiser_thread
+from devil.utils import watchdog_timer
 
 
 class TestException(Exception):
@@ -92,5 +92,20 @@
     event.set()
 
 
+class TestRunAsync(unittest.TestCase):
+  """Tests for reraiser_thread.RunAsync."""
+  def testNoArgs(self):
+    results = reraiser_thread.RunAsync([])
+    self.assertEqual([], results)
+
+  def testOneArg(self):
+    results = reraiser_thread.RunAsync([lambda: 1])
+    self.assertEqual([1], results)
+
+  def testTwoArgs(self):
+    a, b = reraiser_thread.RunAsync((lambda: 1, lambda: 2))
+    self.assertEqual(1, a)
+    self.assertEqual(2, b)
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/build/android/devil/utils/reset_usb.py b/build/android/devil/utils/reset_usb.py
new file mode 100755
index 0000000..3f3b30a
--- /dev/null
+++ b/build/android/devil/utils/reset_usb.py
@@ -0,0 +1,100 @@
+#!/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 argparse
+import fcntl
+import logging
+import re
+import sys
+
+from devil.android import device_errors
+from devil.utils import lsusb
+from devil.utils import run_tests_helper
+
+_INDENTATION_RE = re.compile(r'^( *)')
+_LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}):')
+_LSUSB_ENTRY_RE = re.compile(r'^ *([^ ]+) +([^ ]+) *([^ ].*)?$')
+_LSUSB_GROUP_RE = re.compile(r'^ *([^ ]+.*):$')
+
+_USBDEVFS_RESET = ord('U') << 8 | 20
+
+
+def reset_usb(bus, device):
+  """Reset the USB device with the given bus and device."""
+  usb_file_path = '/dev/bus/usb/%03d/%03d' % (bus, device)
+  with open(usb_file_path, 'w') as usb_file:
+    logging.debug('fcntl.ioctl(%s, %d)', usb_file_path, _USBDEVFS_RESET)
+    fcntl.ioctl(usb_file, _USBDEVFS_RESET)
+
+
+def reset_android_usb(serial):
+  """Reset the USB device for the given Android device."""
+  lsusb_info = lsusb.lsusb()
+
+  bus = None
+  device = None
+  for device_info in lsusb_info:
+    device_serial = lsusb.get_lsusb_serial(device_info)
+    if device_serial == serial:
+      bus = int(device_info.get('bus'))
+      device = int(device_info.get('device'))
+
+  if bus and device:
+    reset_usb(bus, device)
+  else:
+    raise device_errors.DeviceUnreachableError(
+        'Unable to determine bus or device for device %s' % serial)
+
+
+def reset_all_android_devices():
+  """Reset all USB devices that look like an Android device."""
+  _reset_all_matching(lambda i: bool(lsusb.get_lsusb_serial(i)))
+
+
+def _reset_all_matching(condition):
+  lsusb_info = lsusb.lsusb()
+  for device_info in lsusb_info:
+    if int(device_info.get('device')) != 1 and condition(device_info):
+      bus = int(device_info.get('bus'))
+      device = int(device_info.get('device'))
+      try:
+        reset_usb(bus, device)
+        serial = lsusb.get_lsusb_serial(device_info)
+        if serial:
+          logging.info('Reset USB device (bus: %03d, device: %03d, serial: %s)',
+              bus, device, serial)
+        else:
+          logging.info('Reset USB device (bus: %03d, device: %03d)',
+              bus, device)
+      except IOError:
+        logging.error(
+            'Failed to reset USB device (bus: %03d, device: %03d)',
+            bus, device)
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('-v', '--verbose', action='count')
+  parser.add_argument('-s', '--serial')
+  parser.add_argument('--bus', type=int)
+  parser.add_argument('--device', type=int)
+  args = parser.parse_args()
+
+  run_tests_helper.SetLogLevel(args.verbose)
+
+  if args.serial:
+    reset_android_usb(args.serial)
+  elif args.bus and args.device:
+    reset_usb(args.bus, args.device)
+  else:
+    parser.error('Unable to determine target. '
+                 'Specify --serial or BOTH --bus and --device.')
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
+
diff --git a/build/android/devil/utils/run_tests_helper.py b/build/android/devil/utils/run_tests_helper.py
new file mode 100644
index 0000000..43f654d
--- /dev/null
+++ b/build/android/devil/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/devil/utils/timeout_retry.py b/build/android/devil/utils/timeout_retry.py
new file mode 100644
index 0000000..1d748a9
--- /dev/null
+++ b/build/android/devil/utils/timeout_retry.py
@@ -0,0 +1,175 @@
+# Copyright 2013 The Chromium 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 devil.utils import reraiser_thread
+from devil.utils import watchdog_timer
+
+
+
+class TimeoutRetryThreadGroup(reraiser_thread.ReraiserThreadGroup):
+  def __init__(self, timeout, threads=None):
+    super(TimeoutRetryThreadGroup, self).__init__(threads)
+    self._watcher = watchdog_timer.WatchdogTimer(timeout)
+
+  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))
+      raise reraiser_thread.TimeoutError(msg)
+    return remaining
+
+
+def CurrentTimeoutThreadGroup():
+  """Returns the thread group that owns or is blocked on the active thread.
+
+  Returns:
+    Returns None if no TimeoutRetryThreadGroup is tracking the current thread.
+  """
+  thread_group = reraiser_thread.CurrentThreadGroup()
+  while thread_group:
+    if isinstance(thread_group, TimeoutRetryThreadGroup):
+      return thread_group
+    thread_group = thread_group.blocked_parent_thread_group
+  return None
+
+
+def WaitFor(condition, wait_period=5, max_tries=None):
+  """Wait for a condition to become true.
+
+  Repeatedly call the function condition(), with no arguments, until it returns
+  a true value.
+
+  If called within a TimeoutRetryThreadGroup, 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 TimeoutRetryThreadGroup 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
+      TimeoutRetryThreadGroup and the timeout expires.
+  """
+  condition_name = condition.__name__
+  timeout_thread_group = CurrentTimeoutThreadGroup()
+  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_group:
+      # pylint: disable=no-member
+      msg.append('(%.1fs)' % timeout_thread_group.GetElapsedTime())
+    logging.info(' '.join(msg))
+    if result:
+      return result
+    if timeout_thread_group:
+      # pylint: disable=no-member
+      timeout_thread_group.GetRemainingTime(wait_period,
+          msg='Timed out waiting for %r' % condition_name)
+    time.sleep(wait_period)
+  return None
+
+
+def _LogLastException(thread_name, attempt, max_attempts, log_func):
+  log_func('*' * 80)
+  log_func('Exception on thread %s (attempt %d of %d)', thread_name,
+                   attempt, max_attempts)
+  log_func('*' * 80)
+  fmt_exc = ''.join(traceback.format_exc())
+  for line in fmt_exc.splitlines():
+    log_func(line.rstrip())
+  log_func('*' * 80)
+
+
+def Run(func, timeout, retries, args=None, kwargs=None, desc=None,
+        error_log_func=logging.critical):
+  """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|.
+    desc: An optional description of |func| used in logging. If omitted,
+      |func.__name__| will be used.
+    error_log_func: Logging function when logging errors.
+
+  Returns:
+    The return value of func(*args, **kwargs).
+  """
+  if not args:
+    args = []
+  if not kwargs:
+    kwargs = {}
+
+  num_try = 1
+  while True:
+    thread_name = 'TimeoutThread-%d-for-%s' % (num_try,
+                                               threading.current_thread().name)
+    child_thread = reraiser_thread.ReraiserThread(lambda: func(*args, **kwargs),
+                                                  name=thread_name)
+    try:
+      thread_group = TimeoutRetryThreadGroup(timeout, threads=[child_thread])
+      thread_group.StartAll(will_block=True)
+      while True:
+        thread_group.JoinAll(watcher=thread_group.GetWatcher(), timeout=60,
+                             error_log_func=error_log_func)
+        if thread_group.IsAlive():
+          logging.info('Still working on %s', desc if desc else func.__name__)
+        else:
+          return thread_group.GetAllReturnValues()[0]
+    except reraiser_thread.TimeoutError:
+      # Timeouts already get their stacks logged.
+      if num_try > retries:
+        raise
+      # Do not catch KeyboardInterrupt.
+    except Exception:  # pylint: disable=broad-except
+      if num_try > retries:
+        raise
+      _LogLastException(thread_name, num_try, retries + 1, error_log_func)
+    num_try += 1
diff --git a/build/android/devil/utils/timeout_retry_unittest.py b/build/android/devil/utils/timeout_retry_unittest.py
new file mode 100755
index 0000000..f2ceef7
--- /dev/null
+++ b/build/android/devil/utils/timeout_retry_unittest.py
@@ -0,0 +1,77 @@
+#!/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.
+
+"""Unittests for timeout_and_retry.py."""
+
+import logging
+import time
+import unittest
+
+from devil.utils import reraiser_thread
+from devil.utils import timeout_retry
+
+
+_DEFAULT_TIMEOUT = .1
+
+
+class TestException(Exception):
+  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]
+    def _sleep():
+      tries[0] += 1
+      time.sleep(1)
+
+    self.assertRaises(
+        reraiser_thread.TimeoutError, timeout_retry.Run, _sleep, .0001, 1,
+        error_log_func=logging.debug)
+    self.assertEqual(tries[0], 2)
+
+  def testRetries(self):
+    tries = [0]
+    self.assertRaises(
+        TestException, timeout_retry.Run, lambda: _CountTries(tries),
+        _DEFAULT_TIMEOUT, 3, error_log_func=logging.debug)
+    self.assertEqual(tries[0], 4)
+
+  def testNoRetries(self):
+    tries = [0]
+    self.assertRaises(
+        TestException, timeout_retry.Run, lambda: _CountTries(tries),
+        _DEFAULT_TIMEOUT, 0, error_log_func=logging.debug)
+    self.assertEqual(tries[0], 1)
+
+  def testReturnValue(self):
+    self.assertTrue(timeout_retry.Run(lambda: True, _DEFAULT_TIMEOUT, 3))
+
+  def testCurrentTimeoutThreadGroup(self):
+    def InnerFunc():
+      current_thread_group = timeout_retry.CurrentTimeoutThreadGroup()
+      self.assertIsNotNone(current_thread_group)
+      def InnerInnerFunc():
+        self.assertEqual(current_thread_group,
+                         timeout_retry.CurrentTimeoutThreadGroup())
+        return True
+      return reraiser_thread.RunAsync((InnerInnerFunc,))[0]
+
+    self.assertTrue(timeout_retry.Run(InnerFunc, _DEFAULT_TIMEOUT, 3))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/devil/utils/watchdog_timer.py b/build/android/devil/utils/watchdog_timer.py
new file mode 100644
index 0000000..2f4c464
--- /dev/null
+++ b/build/android/devil/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/devil/utils/zip_utils.py b/build/android/devil/utils/zip_utils.py
new file mode 100644
index 0000000..d799463
--- /dev/null
+++ b/build/android/devil/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/dex_action.gypi b/build/android/dex_action.gypi
index 9ea3e71..7d9638e 100644
--- a/build/android/dex_action.gypi
+++ b/build/android/dex_action.gypi
@@ -30,6 +30,8 @@
     'dex_input_paths': [],
     'dex_generated_input_dirs': [],
     'proguard_enabled%': 'false',
+    # TODO(jbudorick): remove this once multidex is done.
+    'debug_build_proguard_enabled%': 'false',
     'proguard_enabled_input_path%': '',
     'dex_no_locals%': 0,
     'dex_additional_options': [],
@@ -48,8 +50,10 @@
     'python', '<(DEPTH)/build/android/gyp/dex.py',
     '--dex-path=<(output_path)',
     '--android-sdk-tools=<(android_sdk_tools)',
+    '--output-directory=<(PRODUCT_DIR)',
     '--configuration-name=<(CONFIGURATION_NAME)',
     '--proguard-enabled=>(proguard_enabled)',
+    '--debug-build-proguard-enabled=>(debug_build_proguard_enabled)',
     '--proguard-enabled-input-path=<(proguard_enabled_input_path)',
     '--no-locals=>(dex_no_locals)',
     '>@(dex_additional_options)',
diff --git a/build/android/disable_lto.gypi b/build/android/disable_gcc_lto.gypi
similarity index 72%
rename from build/android/disable_lto.gypi
rename to build/android/disable_gcc_lto.gypi
index e379cfd..a733c7a 100644
--- a/build/android/disable_lto.gypi
+++ b/build/android/disable_gcc_lto.gypi
@@ -2,13 +2,13 @@
 # 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.
+# This file is meant to be included to disable GCC LTO on a target.
 
 {
   'target_conditions': [
     ['_toolset=="target"', {
       'conditions': [
-        ['OS=="android" and (use_lto==1 or use_lto_o2==1)', {
+        ['OS=="android" and clang==0 and (use_lto==1 or use_lto_o2==1)', {
           'cflags!': [
             '-flto',
             '-ffat-lto-objects',
diff --git a/build/android/emma_coverage_stats.py b/build/android/emma_coverage_stats.py
new file mode 100755
index 0000000..6f64f30
--- /dev/null
+++ b/build/android/emma_coverage_stats.py
@@ -0,0 +1,477 @@
+#!/usr/bin/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.
+
+"""Generates incremental code coverage reports for Java code in Chromium.
+
+Usage:
+
+  build/android/emma_coverage_stats.py -v --out <output file path> --emma-dir
+    <EMMA file directory> --lines-for-coverage-file
+    <path to file containing lines for coverage>
+
+  Creates a JSON representation of the overall and file coverage stats and saves
+  this information to the specified output file.
+"""
+
+import argparse
+import collections
+import json
+import logging
+import os
+import re
+import sys
+from xml.etree import ElementTree
+
+from devil.utils import run_tests_helper
+
+NOT_EXECUTABLE = -1
+NOT_COVERED = 0
+COVERED = 1
+PARTIALLY_COVERED = 2
+
+# Coverage information about a single line of code.
+LineCoverage = collections.namedtuple(
+    'LineCoverage',
+    ['lineno', 'source', 'covered_status', 'fractional_line_coverage'])
+
+
+class _EmmaHtmlParser(object):
+  """Encapsulates HTML file parsing operations.
+
+  This class contains all operations related to parsing HTML files that were
+  produced using the EMMA code coverage tool.
+
+  Example HTML:
+
+  Package links:
+    <a href="_files/1.html">org.chromium.chrome</a>
+    This is returned by the selector |XPATH_SELECT_PACKAGE_ELEMENTS|.
+
+  Class links:
+    <a href="1e.html">DoActivity.java</a>
+    This is returned by the selector |XPATH_SELECT_CLASS_ELEMENTS|.
+
+  Line coverage data:
+    <tr class="p">
+       <td class="l" title="78% line coverage (7 out of 9)">108</td>
+       <td title="78% line coverage (7 out of 9 instructions)">
+         if (index < 0 || index = mSelectors.size()) index = 0;</td>
+    </tr>
+    <tr>
+       <td class="l">109</td>
+       <td> </td>
+    </tr>
+    <tr class="c">
+       <td class="l">110</td>
+       <td>        if (mSelectors.get(index) != null) {</td>
+    </tr>
+    <tr class="z">
+       <td class="l">111</td>
+       <td>            for (int i = 0; i < mSelectors.size(); i++) {</td>
+    </tr>
+    Each <tr> element is returned by the selector |XPATH_SELECT_LOC|.
+
+    We can parse this to get:
+      1. Line number
+      2. Line of source code
+      3. Coverage status (c, z, or p)
+      4. Fractional coverage value (% out of 100 if PARTIALLY_COVERED)
+  """
+  # Selector to match all <a> elements within the rows that are in the table
+  # that displays all of the different packages.
+  _XPATH_SELECT_PACKAGE_ELEMENTS = './/BODY/TABLE[4]/TR/TD/A'
+
+  # Selector to match all <a> elements within the rows that are in the table
+  # that displays all of the different classes within a package.
+  _XPATH_SELECT_CLASS_ELEMENTS = './/BODY/TABLE[3]/TR/TD/A'
+
+  # Selector to match all <tr> elements within the table containing Java source
+  # code in an EMMA HTML file.
+  _XPATH_SELECT_LOC = './/BODY/TABLE[4]/TR'
+
+  # Children of HTML elements are represented as a list in ElementTree. These
+  # constants represent list indices corresponding to relevant child elements.
+
+  # Child 1 contains percentage covered for a line.
+  _ELEMENT_PERCENT_COVERED = 1
+
+  # Child 1 contains the original line of source code.
+  _ELEMENT_CONTAINING_SOURCE_CODE = 1
+
+  # Child 0 contains the line number.
+  _ELEMENT_CONTAINING_LINENO = 0
+
+  # Maps CSS class names to corresponding coverage constants.
+  _CSS_TO_STATUS = {'c': COVERED, 'p': PARTIALLY_COVERED, 'z': NOT_COVERED}
+
+  # UTF-8 no break space.
+  _NO_BREAK_SPACE = '\xc2\xa0'
+
+  def __init__(self, emma_file_base_dir):
+    """Initializes _EmmaHtmlParser.
+
+    Args:
+      emma_file_base_dir: Path to the location where EMMA report files are
+        stored. Should be where index.html is stored.
+    """
+    self._base_dir = emma_file_base_dir
+    self._emma_files_path = os.path.join(self._base_dir, '_files')
+    self._index_path = os.path.join(self._base_dir, 'index.html')
+
+  def GetLineCoverage(self, emma_file_path):
+    """Returns a list of LineCoverage objects for the given EMMA HTML file.
+
+    Args:
+      emma_file_path: String representing the path to the EMMA HTML file.
+
+    Returns:
+      A list of LineCoverage objects.
+    """
+    line_tr_elements = self._FindElements(
+        emma_file_path, self._XPATH_SELECT_LOC)
+    line_coverage = []
+    for tr in line_tr_elements:
+      # Get the coverage status.
+      coverage_status = self._CSS_TO_STATUS.get(tr.get('CLASS'), NOT_EXECUTABLE)
+      # Get the fractional coverage value.
+      if coverage_status == PARTIALLY_COVERED:
+        title_attribute = (tr[self._ELEMENT_PERCENT_COVERED].get('TITLE'))
+        # Parse string that contains percent covered: "83% line coverage ...".
+        percent_covered = title_attribute.split('%')[0]
+        fractional_coverage = int(percent_covered) / 100.0
+      else:
+        fractional_coverage = 1.0
+
+      # Get the line number.
+      lineno_element = tr[self._ELEMENT_CONTAINING_LINENO]
+      # Handles oddly formatted HTML (where there is an extra <a> tag).
+      lineno = int(lineno_element.text or
+                   lineno_element[self._ELEMENT_CONTAINING_LINENO].text)
+      # Get the original line of Java source code.
+      raw_source = tr[self._ELEMENT_CONTAINING_SOURCE_CODE].text
+      utf8_source = raw_source.encode('UTF-8')
+      source = utf8_source.replace(self._NO_BREAK_SPACE, ' ')
+
+      line = LineCoverage(lineno, source, coverage_status, fractional_coverage)
+      line_coverage.append(line)
+
+    return line_coverage
+
+  def GetPackageNameToEmmaFileDict(self):
+    """Returns a dict mapping Java packages to EMMA HTML coverage files.
+
+    Parses the EMMA index.html file to get a list of packages, then parses each
+    package HTML file to get a list of classes for that package, and creates
+    a dict with this info.
+
+    Returns:
+      A dict mapping string representation of Java packages (with class
+        names appended) to the corresponding file paths of EMMA HTML files.
+    """
+    # These <a> elements contain each package name and the path of the file
+    # where all classes within said package are listed.
+    package_link_elements = self._FindElements(
+        self._index_path, self._XPATH_SELECT_PACKAGE_ELEMENTS)
+    # Maps file path of package directory (EMMA generated) to package name.
+    # Example: emma_dir/f.html: org.chromium.chrome.
+    package_links = {
+      os.path.join(self._base_dir, link.attrib['HREF']): link.text
+      for link in package_link_elements if 'HREF' in link.attrib
+    }
+
+    package_to_emma = {}
+    for package_emma_file_path, package_name in package_links.iteritems():
+      # These <a> elements contain each class name in the current package and
+      # the path of the file where the coverage info is stored for each class.
+      coverage_file_link_elements = self._FindElements(
+          package_emma_file_path, self._XPATH_SELECT_CLASS_ELEMENTS)
+
+      for class_name_element in coverage_file_link_elements:
+        emma_coverage_file_path = os.path.join(
+            self._emma_files_path, class_name_element.attrib['HREF'])
+        full_package_name = '%s.%s' % (package_name, class_name_element.text)
+        package_to_emma[full_package_name] = emma_coverage_file_path
+
+    return package_to_emma
+
+  # pylint: disable=no-self-use
+  def _FindElements(self, file_path, xpath_selector):
+    """Reads a HTML file and performs an XPath match.
+
+    Args:
+      file_path: String representing the path to the HTML file.
+      xpath_selector: String representing xpath search pattern.
+
+    Returns:
+      A list of ElementTree.Elements matching the given XPath selector.
+        Returns an empty list if there is no match.
+    """
+    with open(file_path) as f:
+      file_contents = f.read().decode('ISO-8859-1').encode('UTF-8')
+      root = ElementTree.fromstring(file_contents)
+      return root.findall(xpath_selector)
+
+
+class _EmmaCoverageStats(object):
+  """Computes code coverage stats for Java code using the coverage tool EMMA.
+
+  This class provides an API that allows users to capture absolute code coverage
+  and code coverage on a subset of lines for each Java source file. Coverage
+  reports are generated in JSON format.
+  """
+  # Regular expression to get package name from Java package statement.
+  RE_PACKAGE_MATCH_GROUP = 'package'
+  RE_PACKAGE = re.compile(r'package (?P<%s>[\w.]*);' % RE_PACKAGE_MATCH_GROUP)
+
+  def __init__(self, emma_file_base_dir, files_for_coverage):
+    """Initialize _EmmaCoverageStats.
+
+    Args:
+      emma_file_base_dir: String representing the path to the base directory
+        where EMMA HTML coverage files are stored, i.e. parent of index.html.
+      files_for_coverage: A list of Java source code file paths to get EMMA
+        coverage for.
+    """
+    self._emma_parser = _EmmaHtmlParser(emma_file_base_dir)
+    self._source_to_emma = self._GetSourceFileToEmmaFileDict(files_for_coverage)
+
+  def GetCoverageDict(self, lines_for_coverage):
+    """Returns a dict containing detailed coverage information.
+
+    Gets detailed coverage stats for each file specified in the
+    |lines_for_coverage| dict and the total incremental number of lines covered
+    and executable for all files in |lines_for_coverage|.
+
+    Args:
+      lines_for_coverage: A dict mapping Java source file paths to lists of line
+        numbers.
+
+    Returns:
+      A dict containing coverage stats for the given dict of files and lines.
+        Contains absolute coverage stats for each file, coverage stats for each
+        file's lines specified in |lines_for_coverage|, line by line coverage
+        for each file, and overall coverage stats for the lines specified in
+        |lines_for_coverage|.
+    """
+    file_coverage = {}
+    for file_path, line_numbers in lines_for_coverage.iteritems():
+      file_coverage_dict = self.GetCoverageDictForFile(file_path, line_numbers)
+      if file_coverage_dict:
+        file_coverage[file_path] = file_coverage_dict
+      else:
+        logging.warning(
+            'No code coverage data for %s, skipping.', file_path)
+
+    covered_statuses = [s['incremental'] for s in file_coverage.itervalues()]
+    num_covered_lines = sum(s['covered'] for s in covered_statuses)
+    num_total_lines = sum(s['total'] for s in covered_statuses)
+    return {
+      'files': file_coverage,
+      'patch': {
+        'incremental': {
+          'covered': num_covered_lines,
+          'total': num_total_lines
+        }
+      }
+    }
+
+  def GetCoverageDictForFile(self, file_path, line_numbers):
+    """Returns a dict containing detailed coverage info for the given file.
+
+    Args:
+      file_path: The path to the Java source file that we want to create the
+        coverage dict for.
+      line_numbers: A list of integer line numbers to retrieve additional stats
+        for.
+
+    Returns:
+      A dict containing absolute, incremental, and line by line coverage for
+        a file.
+    """
+    if file_path not in self._source_to_emma:
+      return None
+    emma_file = self._source_to_emma[file_path]
+    total_line_coverage = self._emma_parser.GetLineCoverage(emma_file)
+    incremental_line_coverage = [line for line in total_line_coverage
+                                 if line.lineno in line_numbers]
+    line_by_line_coverage = [
+      {
+        'line': line.source,
+        'coverage': line.covered_status,
+        'changed': line.lineno in line_numbers,
+        'fractional_coverage': line.fractional_line_coverage,
+      }
+      for line in total_line_coverage
+    ]
+    total_covered_lines, total_lines = (
+        self.GetSummaryStatsForLines(total_line_coverage))
+    incremental_covered_lines, incremental_total_lines = (
+        self.GetSummaryStatsForLines(incremental_line_coverage))
+
+    file_coverage_stats = {
+      'absolute': {
+        'covered': total_covered_lines,
+        'total': total_lines
+      },
+      'incremental': {
+        'covered': incremental_covered_lines,
+        'total': incremental_total_lines
+      },
+      'source': line_by_line_coverage,
+    }
+    return file_coverage_stats
+
+  # pylint: disable=no-self-use
+  def GetSummaryStatsForLines(self, line_coverage):
+    """Gets summary stats for a given list of LineCoverage objects.
+
+    Args:
+      line_coverage: A list of LineCoverage objects.
+
+    Returns:
+      A tuple containing the number of lines that are covered and the total
+        number of lines that are executable, respectively
+    """
+    partially_covered_sum = 0
+    covered_status_totals = {COVERED: 0, NOT_COVERED: 0, PARTIALLY_COVERED: 0}
+    for line in line_coverage:
+      status = line.covered_status
+      if status == NOT_EXECUTABLE:
+        continue
+      covered_status_totals[status] += 1
+      if status == PARTIALLY_COVERED:
+        partially_covered_sum += line.fractional_line_coverage
+
+    total_covered = covered_status_totals[COVERED] + partially_covered_sum
+    total_lines = sum(covered_status_totals.values())
+    return total_covered, total_lines
+
+  def _GetSourceFileToEmmaFileDict(self, files):
+    """Gets a dict used to correlate Java source files with EMMA HTML files.
+
+    This method gathers the information needed to correlate EMMA HTML
+    files with Java source files. EMMA XML and plain text reports do not provide
+    line by line coverage data, so HTML reports must be used instead.
+    Unfortunately, the HTML files that are created are given garbage names
+    (i.e 1.html) so we need to manually correlate EMMA HTML files
+    with the original Java source files.
+
+    Args:
+      files: A list of file names for which coverage information is desired.
+
+    Returns:
+      A dict mapping Java source file paths to EMMA HTML file paths.
+    """
+    # Maps Java source file paths to package names.
+    # Example: /usr/code/file.java -> org.chromium.file.java.
+    source_to_package = {}
+    for file_path in files:
+      package = self.GetPackageNameFromFile(file_path)
+      if package:
+        source_to_package[file_path] = package
+      else:
+        logging.warning("Skipping %s because it doesn\'t have a package "
+                        "statement.", file_path)
+
+    # Maps package names to EMMA report HTML files.
+    # Example: org.chromium.file.java -> out/coverage/1a.html.
+    package_to_emma = self._emma_parser.GetPackageNameToEmmaFileDict()
+    # Finally, we have a dict mapping Java file paths to EMMA report files.
+    # Example: /usr/code/file.java -> out/coverage/1a.html.
+    source_to_emma = {source: package_to_emma[package]
+                      for source, package in source_to_package.iteritems()
+                      if package in package_to_emma}
+    return source_to_emma
+
+  @staticmethod
+  def NeedsCoverage(file_path):
+    """Checks to see if the file needs to be analyzed for code coverage.
+
+    Args:
+      file_path: A string representing path to the file.
+
+    Returns:
+      True for Java files that exist, False for all others.
+    """
+    if os.path.splitext(file_path)[1] == '.java' and os.path.exists(file_path):
+      return True
+    else:
+      logging.info('Skipping file %s, cannot compute code coverage.', file_path)
+      return False
+
+  @staticmethod
+  def GetPackageNameFromFile(file_path):
+    """Gets the full package name including the file name for a given file path.
+
+    Args:
+      file_path: String representing the path to the Java source file.
+
+    Returns:
+      A string representing the full package name with file name appended or
+        None if there is no package statement in the file.
+    """
+    with open(file_path) as f:
+      file_content = f.read()
+      package_match = re.search(_EmmaCoverageStats.RE_PACKAGE, file_content)
+      if package_match:
+        package = package_match.group(_EmmaCoverageStats.RE_PACKAGE_MATCH_GROUP)
+        file_name = os.path.basename(file_path)
+        return '%s.%s' % (package, file_name)
+      else:
+        return None
+
+
+def GenerateCoverageReport(line_coverage_file, out_file_path, coverage_dir):
+  """Generates a coverage report for a given set of lines.
+
+  Writes the results of the coverage analysis to the file specified by
+  |out_file_path|.
+
+  Args:
+    line_coverage_file: The path to a file which contains a dict mapping file
+      names to lists of line numbers. Example: {file1: [1, 2, 3], ...} means
+      that we should compute coverage information on lines 1 - 3 for file1.
+    out_file_path: A string representing the location to write the JSON report.
+    coverage_dir: A string representing the file path where the EMMA
+      HTML coverage files are located (i.e. folder where index.html is located).
+  """
+  with open(line_coverage_file) as f:
+    potential_files_for_coverage = json.load(f)
+
+  files_for_coverage = {f: lines
+                        for f, lines in potential_files_for_coverage.iteritems()
+                        if _EmmaCoverageStats.NeedsCoverage(f)}
+
+  coverage_results = {}
+  if files_for_coverage:
+    code_coverage = _EmmaCoverageStats(coverage_dir, files_for_coverage.keys())
+    coverage_results = code_coverage.GetCoverageDict(files_for_coverage)
+  else:
+    logging.info('No Java files requiring coverage were included in %s.',
+                 line_coverage_file)
+
+  with open(out_file_path, 'w+') as out_status_file:
+    json.dump(coverage_results, out_status_file)
+
+
+def main():
+  argparser = argparse.ArgumentParser()
+  argparser.add_argument('--out', required=True, type=str,
+                         help='Report output file path.')
+  argparser.add_argument('--emma-dir', required=True, type=str,
+                         help='EMMA HTML report directory.')
+  argparser.add_argument('--lines-for-coverage-file', required=True, type=str,
+                         help='File containing a JSON object. Should contain a '
+                         'dict mapping file names to lists of line numbers of '
+                         'code for which coverage information is desired.')
+  argparser.add_argument('-v', '--verbose', action='count',
+                         help='Print verbose log information.')
+  args = argparser.parse_args()
+  run_tests_helper.SetLogLevel(args.verbose)
+  GenerateCoverageReport(args.lines_for_coverage_file, args.out, args.emma_dir)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/emma_coverage_stats_test.py b/build/android/emma_coverage_stats_test.py
new file mode 100755
index 0000000..c39dd47
--- /dev/null
+++ b/build/android/emma_coverage_stats_test.py
@@ -0,0 +1,566 @@
+#!/usr/bin/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.
+
+# pylint: disable=protected-access
+
+import os
+import sys
+import unittest
+from xml.etree import ElementTree
+
+import emma_coverage_stats
+from pylib import constants
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock  # pylint: disable=import-error
+
+EMPTY_COVERAGE_STATS_DICT = {
+  'files': {},
+  'patch': {
+    'incremental': {
+      'covered': 0, 'total': 0
+    }
+  }
+}
+
+
+class _EmmaHtmlParserTest(unittest.TestCase):
+  """Tests for _EmmaHtmlParser.
+
+  Uses modified EMMA report HTML that contains only the subset of tags needed
+  for test verification.
+  """
+
+  def setUp(self):
+    self.emma_dir = 'fake/dir/'
+    self.parser = emma_coverage_stats._EmmaHtmlParser(self.emma_dir)
+    self.simple_html = '<TR><TD CLASS="p">Test HTML</TD></TR>'
+    self.index_html = (
+      '<HTML>'
+        '<BODY>'
+          '<TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">'
+          '</TABLE>'
+          '<TABLE CELLSPACING="0" WIDTH="100%">'
+          '</TABLE>'
+          '<TABLE CLASS="it" CELLSPACING="0">'
+          '</TABLE>'
+          '<TABLE CELLSPACING="0" WIDTH="100%">'
+            '<TR>'
+              '<TH CLASS="f">name</TH>'
+              '<TH>class, %</TH>'
+              '<TH>method, %</TH>'
+              '<TH>block, %</TH>'
+              '<TH>line, %</TH>'
+            '</TR>'
+            '<TR CLASS="o">'
+              '<TD><A HREF="_files/0.html"'
+              '>org.chromium.chrome.browser</A></TD>'
+              '<TD CLASS="h">0%   (0/3)</TD>'
+            '</TR>'
+            '<TR>'
+              '<TD><A HREF="_files/1.html"'
+              '>org.chromium.chrome.browser.tabmodel</A></TD>'
+              '<TD CLASS="h">0%   (0/8)</TD>'
+            '</TR>'
+          '</TABLE>'
+          '<TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">'
+          '</TABLE>'
+        '</BODY>'
+      '</HTML>'
+    )
+    self.package_1_class_list_html = (
+      '<HTML>'
+        '<BODY>'
+          '<TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">'
+          '</TABLE>'
+          '<TABLE CELLSPACING="0" WIDTH="100%">'
+          '</TABLE>'
+          '<TABLE CELLSPACING="0" WIDTH="100%">'
+            '<TR>'
+              '<TH CLASS="f">name</TH>'
+              '<TH>class, %</TH>'
+              '<TH>method, %</TH>'
+              '<TH>block, %</TH>'
+              '<TH>line, %</TH>'
+            '</TR>'
+            '<TR CLASS="o">'
+              '<TD><A HREF="1e.html">IntentHelper.java</A></TD>'
+              '<TD CLASS="h">0%   (0/3)</TD>'
+              '<TD CLASS="h">0%   (0/9)</TD>'
+              '<TD CLASS="h">0%   (0/97)</TD>'
+              '<TD CLASS="h">0%   (0/26)</TD>'
+            '</TR>'
+          '</TABLE>'
+          '<TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">'
+          '</TABLE>'
+        '</BODY>'
+      '</HTML>'
+    )
+    self.package_2_class_list_html = (
+      '<HTML>'
+        '<BODY>'
+          '<TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">'
+          '</TABLE>'
+          '<TABLE CELLSPACING="0" WIDTH="100%">'
+          '</TABLE>'
+          '<TABLE CELLSPACING="0" WIDTH="100%">'
+            '<TR>'
+              '<TH CLASS="f">name</TH>'
+              '<TH>class, %</TH>'
+              '<TH>method, %</TH>'
+              '<TH>block, %</TH>'
+              '<TH>line, %</TH>'
+            '</TR>'
+            '<TR CLASS="o">'
+              '<TD><A HREF="1f.html">ContentSetting.java</A></TD>'
+              '<TD CLASS="h">0%   (0/1)</TD>'
+            '</TR>'
+            '<TR>'
+              '<TD><A HREF="20.html">DevToolsServer.java</A></TD>'
+            '</TR>'
+            '<TR CLASS="o">'
+              '<TD><A HREF="21.html">FileProviderHelper.java</A></TD>'
+            '</TR>'
+            '<TR>'
+              '<TD><A HREF="22.html">ContextualMenuBar.java</A></TD>'
+            '</TR>'
+            '<TR CLASS="o">'
+              '<TD><A HREF="23.html">AccessibilityUtil.java</A></TD>'
+            '</TR>'
+            '<TR>'
+              '<TD><A HREF="24.html">NavigationPopup.java</A></TD>'
+            '</TR>'
+          '</TABLE>'
+          '<TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">'
+          '</TABLE>'
+        '</BODY>'
+      '</HTML>'
+    )
+    self.partially_covered_tr_html = (
+      '<TR CLASS="p">'
+        '<TD CLASS="l" TITLE="78% line coverage (7 out of 9)">108</TD>'
+        '<TD TITLE="78% line coverage (7 out of 9 instructions)">'
+          'if (index &lt; 0 || index = mSelectors.size()) index = 0;</TD>'
+      '</TR>'
+    )
+    self.covered_tr_html = (
+      '<TR CLASS="c">'
+        '<TD CLASS="l">110</TD>'
+        '<TD>        if (mSelectors.get(index) != null) {</TD>'
+      '</TR>'
+    )
+    self.not_executable_tr_html = (
+      '<TR>'
+        '<TD CLASS="l">109</TD>'
+        '<TD> </TD>'
+      '</TR>'
+    )
+    self.tr_with_extra_a_tag = (
+      '<TR CLASS="z">'
+        '<TD CLASS="l">'
+          '<A name="1f">54</A>'
+        '</TD>'
+        '<TD>            }</TD>'
+      '</TR>'
+    )
+
+  def testInit(self):
+    emma_dir = self.emma_dir
+    parser = emma_coverage_stats._EmmaHtmlParser(emma_dir)
+    self.assertEqual(parser._base_dir, emma_dir)
+    self.assertEqual(parser._emma_files_path, 'fake/dir/_files')
+    self.assertEqual(parser._index_path, 'fake/dir/index.html')
+
+  def testFindElements_basic(self):
+    read_values = [self.simple_html]
+    found, _ = MockOpenForFunction(self.parser._FindElements, read_values,
+                                   file_path='fake', xpath_selector='.//TD')
+    self.assertIs(type(found), list)
+    self.assertIs(type(found[0]), ElementTree.Element)
+    self.assertEqual(found[0].text, 'Test HTML')
+
+  def testFindElements_multipleElements(self):
+    multiple_trs = self.not_executable_tr_html + self.covered_tr_html
+    read_values = ['<div>' + multiple_trs + '</div>']
+    found, _ = MockOpenForFunction(self.parser._FindElements, read_values,
+                                   file_path='fake', xpath_selector='.//TR')
+    self.assertEquals(2, len(found))
+
+  def testFindElements_noMatch(self):
+    read_values = [self.simple_html]
+    found, _ = MockOpenForFunction(self.parser._FindElements, read_values,
+                                   file_path='fake', xpath_selector='.//TR')
+    self.assertEqual(found, [])
+
+  def testFindElements_badFilePath(self):
+    with self.assertRaises(IOError):
+      with mock.patch('os.path.exists', return_value=False):
+        self.parser._FindElements('fake', xpath_selector='//tr')
+
+  def testGetPackageNameToEmmaFileDict_basic(self):
+    expected_dict = {
+      'org.chromium.chrome.browser.AccessibilityUtil.java':
+      'fake/dir/_files/23.html',
+      'org.chromium.chrome.browser.ContextualMenuBar.java':
+      'fake/dir/_files/22.html',
+      'org.chromium.chrome.browser.tabmodel.IntentHelper.java':
+      'fake/dir/_files/1e.html',
+      'org.chromium.chrome.browser.ContentSetting.java':
+      'fake/dir/_files/1f.html',
+      'org.chromium.chrome.browser.DevToolsServer.java':
+      'fake/dir/_files/20.html',
+      'org.chromium.chrome.browser.NavigationPopup.java':
+      'fake/dir/_files/24.html',
+      'org.chromium.chrome.browser.FileProviderHelper.java':
+      'fake/dir/_files/21.html'}
+
+    read_values = [self.index_html, self.package_1_class_list_html,
+                   self.package_2_class_list_html]
+    return_dict, mock_open = MockOpenForFunction(
+        self.parser.GetPackageNameToEmmaFileDict, read_values)
+
+    self.assertDictEqual(return_dict, expected_dict)
+    self.assertEqual(mock_open.call_count, 3)
+    calls = [mock.call('fake/dir/index.html'),
+             mock.call('fake/dir/_files/1.html'),
+             mock.call('fake/dir/_files/0.html')]
+    mock_open.assert_has_calls(calls)
+
+  def testGetPackageNameToEmmaFileDict_noPackageElements(self):
+    self.parser._FindElements = mock.Mock(return_value=[])
+    return_dict = self.parser.GetPackageNameToEmmaFileDict()
+    self.assertDictEqual({}, return_dict)
+
+  def testGetLineCoverage_status_basic(self):
+    line_coverage = self.GetLineCoverageWithFakeElements([self.covered_tr_html])
+    self.assertEqual(line_coverage[0].covered_status,
+                     emma_coverage_stats.COVERED)
+
+  def testGetLineCoverage_status_statusMissing(self):
+    line_coverage = self.GetLineCoverageWithFakeElements(
+        [self.not_executable_tr_html])
+    self.assertEqual(line_coverage[0].covered_status,
+                     emma_coverage_stats.NOT_EXECUTABLE)
+
+  def testGetLineCoverage_fractionalCoverage_basic(self):
+    line_coverage = self.GetLineCoverageWithFakeElements([self.covered_tr_html])
+    self.assertEqual(line_coverage[0].fractional_line_coverage, 1.0)
+
+  def testGetLineCoverage_fractionalCoverage_partial(self):
+    line_coverage = self.GetLineCoverageWithFakeElements(
+        [self.partially_covered_tr_html])
+    self.assertEqual(line_coverage[0].fractional_line_coverage, 0.78)
+
+  def testGetLineCoverage_lineno_basic(self):
+    line_coverage = self.GetLineCoverageWithFakeElements([self.covered_tr_html])
+    self.assertEqual(line_coverage[0].lineno, 110)
+
+  def testGetLineCoverage_lineno_withAlternativeHtml(self):
+    line_coverage = self.GetLineCoverageWithFakeElements(
+        [self.tr_with_extra_a_tag])
+    self.assertEqual(line_coverage[0].lineno, 54)
+
+  def testGetLineCoverage_source(self):
+    self.parser._FindElements = mock.Mock(
+        return_value=[ElementTree.fromstring(self.covered_tr_html)])
+    line_coverage = self.parser.GetLineCoverage('fake_path')
+    self.assertEqual(line_coverage[0].source,
+                     '        if (mSelectors.get(index) != null) {')
+
+  def testGetLineCoverage_multipleElements(self):
+    line_coverage = self.GetLineCoverageWithFakeElements(
+        [self.covered_tr_html, self.partially_covered_tr_html,
+         self.tr_with_extra_a_tag])
+    self.assertEqual(len(line_coverage), 3)
+
+  def GetLineCoverageWithFakeElements(self, html_elements):
+    """Wraps GetLineCoverage so mock HTML can easily be used.
+
+    Args:
+      html_elements: List of strings each representing an HTML element.
+
+    Returns:
+      A list of LineCoverage objects.
+    """
+    elements = [ElementTree.fromstring(string) for string in html_elements]
+    with mock.patch('emma_coverage_stats._EmmaHtmlParser._FindElements',
+                    return_value=elements):
+      return self.parser.GetLineCoverage('fake_path')
+
+
+class _EmmaCoverageStatsTest(unittest.TestCase):
+  """Tests for _EmmaCoverageStats."""
+
+  def setUp(self):
+    self.good_source_to_emma = {
+      '/path/to/1/File1.java': '/emma/1.html',
+      '/path/2/File2.java': '/emma/2.html',
+      '/path/2/File3.java': '/emma/3.html'
+    }
+    self.line_coverage = [
+        emma_coverage_stats.LineCoverage(
+            1, '', emma_coverage_stats.COVERED, 1.0),
+        emma_coverage_stats.LineCoverage(
+            2, '', emma_coverage_stats.COVERED, 1.0),
+        emma_coverage_stats.LineCoverage(
+            3, '', emma_coverage_stats.NOT_EXECUTABLE, 1.0),
+        emma_coverage_stats.LineCoverage(
+            4, '', emma_coverage_stats.NOT_COVERED, 1.0),
+        emma_coverage_stats.LineCoverage(
+            5, '', emma_coverage_stats.PARTIALLY_COVERED, 0.85),
+        emma_coverage_stats.LineCoverage(
+            6, '', emma_coverage_stats.PARTIALLY_COVERED, 0.20)
+    ]
+    self.lines_for_coverage = [1, 3, 5, 6]
+    with mock.patch('emma_coverage_stats._EmmaHtmlParser._FindElements',
+                    return_value=[]):
+      self.simple_coverage = emma_coverage_stats._EmmaCoverageStats(
+          'fake_dir', {})
+
+  def testInit(self):
+    coverage_stats = self.simple_coverage
+    self.assertIsInstance(coverage_stats._emma_parser,
+                          emma_coverage_stats._EmmaHtmlParser)
+    self.assertIsInstance(coverage_stats._source_to_emma, dict)
+
+  def testNeedsCoverage_withExistingJavaFile(self):
+    test_file = '/path/to/file/File.java'
+    with mock.patch('os.path.exists', return_value=True):
+      self.assertTrue(
+          emma_coverage_stats._EmmaCoverageStats.NeedsCoverage(test_file))
+
+  def testNeedsCoverage_withNonJavaFile(self):
+    test_file = '/path/to/file/File.c'
+    with mock.patch('os.path.exists', return_value=True):
+      self.assertFalse(
+          emma_coverage_stats._EmmaCoverageStats.NeedsCoverage(test_file))
+
+  def testNeedsCoverage_fileDoesNotExist(self):
+    test_file = '/path/to/file/File.java'
+    with mock.patch('os.path.exists', return_value=False):
+      self.assertFalse(
+          emma_coverage_stats._EmmaCoverageStats.NeedsCoverage(test_file))
+
+  def testGetPackageNameFromFile_basic(self):
+    test_file_text = """// Test Copyright
+    package org.chromium.chrome.browser;
+    import android.graphics.RectF;"""
+    result_package, _ = MockOpenForFunction(
+        emma_coverage_stats._EmmaCoverageStats.GetPackageNameFromFile,
+        [test_file_text], file_path='/path/to/file/File.java')
+    self.assertEqual(result_package, 'org.chromium.chrome.browser.File.java')
+
+  def testGetPackageNameFromFile_noPackageStatement(self):
+    result_package, _ = MockOpenForFunction(
+        emma_coverage_stats._EmmaCoverageStats.GetPackageNameFromFile,
+        ['not a package statement'], file_path='/path/to/file/File.java')
+    self.assertIsNone(result_package)
+
+  def testGetSummaryStatsForLines_basic(self):
+    covered, total = self.simple_coverage.GetSummaryStatsForLines(
+        self.line_coverage)
+    self.assertEqual(covered, 3.05)
+    self.assertEqual(total, 5)
+
+  def testGetSourceFileToEmmaFileDict(self):
+    package_names = {
+      '/path/to/1/File1.java': 'org.fake.one.File1.java',
+      '/path/2/File2.java': 'org.fake.File2.java',
+      '/path/2/File3.java': 'org.fake.File3.java'
+    }
+    package_to_emma = {
+      'org.fake.one.File1.java': '/emma/1.html',
+      'org.fake.File2.java': '/emma/2.html',
+      'org.fake.File3.java': '/emma/3.html'
+    }
+    with mock.patch('os.path.exists', return_value=True):
+      coverage_stats = self.simple_coverage
+      coverage_stats._emma_parser.GetPackageNameToEmmaFileDict = mock.MagicMock(
+          return_value=package_to_emma)
+      coverage_stats.GetPackageNameFromFile = lambda x: package_names[x]
+      result_dict = coverage_stats._GetSourceFileToEmmaFileDict(
+          package_names.keys())
+    self.assertDictEqual(result_dict, self.good_source_to_emma)
+
+  def testGetCoverageDictForFile(self):
+    line_coverage = self.line_coverage
+    self.simple_coverage._emma_parser.GetLineCoverage = lambda x: line_coverage
+    self.simple_coverage._source_to_emma = {'/fake/src': 'fake/emma'}
+    lines = self.lines_for_coverage
+    expected_dict = {
+      'absolute': {
+        'covered': 3.05,
+        'total': 5
+      },
+      'incremental': {
+        'covered': 2.05,
+        'total': 3
+      },
+      'source': [
+        {
+          'line': line_coverage[0].source,
+          'coverage': line_coverage[0].covered_status,
+          'changed': True,
+          'fractional_coverage': line_coverage[0].fractional_line_coverage,
+        },
+        {
+          'line': line_coverage[1].source,
+          'coverage': line_coverage[1].covered_status,
+          'changed': False,
+          'fractional_coverage': line_coverage[1].fractional_line_coverage,
+        },
+        {
+          'line': line_coverage[2].source,
+          'coverage': line_coverage[2].covered_status,
+          'changed': True,
+          'fractional_coverage': line_coverage[2].fractional_line_coverage,
+        },
+        {
+          'line': line_coverage[3].source,
+          'coverage': line_coverage[3].covered_status,
+          'changed': False,
+          'fractional_coverage': line_coverage[3].fractional_line_coverage,
+        },
+        {
+          'line': line_coverage[4].source,
+          'coverage': line_coverage[4].covered_status,
+          'changed': True,
+          'fractional_coverage': line_coverage[4].fractional_line_coverage,
+        },
+        {
+          'line': line_coverage[5].source,
+          'coverage': line_coverage[5].covered_status,
+          'changed': True,
+          'fractional_coverage': line_coverage[5].fractional_line_coverage,
+        }
+      ]
+    }
+    result_dict = self.simple_coverage.GetCoverageDictForFile(
+        '/fake/src', lines)
+    self.assertDictEqual(result_dict, expected_dict)
+
+  def testGetCoverageDictForFile_emptyCoverage(self):
+    expected_dict = {
+      'absolute': {'covered': 0, 'total': 0},
+      'incremental': {'covered': 0, 'total': 0},
+      'source': []
+    }
+    self.simple_coverage._emma_parser.GetLineCoverage = lambda x: []
+    self.simple_coverage._source_to_emma = {'fake_dir': 'fake/emma'}
+    result_dict = self.simple_coverage.GetCoverageDictForFile('fake_dir', {})
+    self.assertDictEqual(result_dict, expected_dict)
+
+  def testGetCoverageDictForFile_missingCoverage(self):
+    self.simple_coverage._source_to_emma = {}
+    result_dict = self.simple_coverage.GetCoverageDictForFile('fake_file', {})
+    self.assertIsNone(result_dict)
+
+  def testGetCoverageDict_basic(self):
+    files_for_coverage = {
+      '/path/to/1/File1.java': [1, 3, 4],
+      '/path/2/File2.java': [1, 2]
+    }
+    self.simple_coverage._source_to_emma = {
+      '/path/to/1/File1.java': 'emma_1',
+      '/path/2/File2.java': 'emma_2'
+    }
+    coverage_info = {
+      'emma_1': [
+        emma_coverage_stats.LineCoverage(
+            1, '', emma_coverage_stats.COVERED, 1.0),
+        emma_coverage_stats.LineCoverage(
+            2, '', emma_coverage_stats.PARTIALLY_COVERED, 0.5),
+        emma_coverage_stats.LineCoverage(
+            3, '', emma_coverage_stats.NOT_EXECUTABLE, 1.0),
+        emma_coverage_stats.LineCoverage(
+            4, '', emma_coverage_stats.COVERED, 1.0)
+      ],
+      'emma_2': [
+        emma_coverage_stats.LineCoverage(
+            1, '', emma_coverage_stats.NOT_COVERED, 1.0),
+        emma_coverage_stats.LineCoverage(
+            2, '', emma_coverage_stats.COVERED, 1.0)
+      ]
+    }
+    expected_dict = {
+      'files': {
+        '/path/2/File2.java': {
+          'absolute': {'covered': 1, 'total': 2},
+          'incremental': {'covered': 1, 'total': 2},
+          'source': [{'changed': True, 'coverage': 0,
+                      'line': '', 'fractional_coverage': 1.0},
+                     {'changed': True, 'coverage': 1,
+                      'line': '', 'fractional_coverage': 1.0}]
+        },
+        '/path/to/1/File1.java': {
+          'absolute': {'covered': 2.5, 'total': 3},
+          'incremental': {'covered': 2, 'total': 2},
+          'source': [{'changed': True, 'coverage': 1,
+                      'line': '', 'fractional_coverage': 1.0},
+                     {'changed': False, 'coverage': 2,
+                      'line': '', 'fractional_coverage': 0.5},
+                     {'changed': True, 'coverage': -1,
+                      'line': '', 'fractional_coverage': 1.0},
+                     {'changed': True, 'coverage': 1,
+                      'line': '', 'fractional_coverage': 1.0}]
+        }
+      },
+      'patch': {'incremental': {'covered': 3, 'total': 4}}
+    }
+    # Return the relevant coverage info for each file.
+    self.simple_coverage._emma_parser.GetLineCoverage = (
+        lambda x: coverage_info[x])
+    result_dict = self.simple_coverage.GetCoverageDict(files_for_coverage)
+    self.assertDictEqual(result_dict, expected_dict)
+
+  def testGetCoverageDict_noCoverage(self):
+    result_dict = self.simple_coverage.GetCoverageDict({})
+    self.assertDictEqual(result_dict, EMPTY_COVERAGE_STATS_DICT)
+
+
+class EmmaCoverageStatsGenerateCoverageReport(unittest.TestCase):
+  """Tests for GenerateCoverageReport."""
+
+  def testGenerateCoverageReport_missingJsonFile(self):
+    with self.assertRaises(IOError):
+      with mock.patch('os.path.exists', return_value=False):
+        emma_coverage_stats.GenerateCoverageReport('', '', '')
+
+  def testGenerateCoverageReport_invalidJsonFile(self):
+    with self.assertRaises(ValueError):
+      with mock.patch('os.path.exists', return_value=True):
+        MockOpenForFunction(emma_coverage_stats.GenerateCoverageReport, [''],
+                            line_coverage_file='', out_file_path='',
+                            coverage_dir='')
+
+
+def MockOpenForFunction(func, side_effects, **kwargs):
+  """Allows easy mock open and read for callables that open multiple files.
+
+  Will mock the python open function in a way such that each time read() is
+  called on an open file, the next element in |side_effects| is returned. This
+  makes it easier to test functions that call open() multiple times.
+
+  Args:
+    func: The callable to invoke once mock files are setup.
+    side_effects: A list of return values for each file to return once read.
+      Length of list should be equal to the number calls to open in |func|.
+    **kwargs: Keyword arguments to be passed to |func|.
+
+  Returns:
+    A tuple containing the return value of |func| and the MagicMock object used
+      to mock all calls to open respectively.
+  """
+  mock_open = mock.mock_open()
+  mock_open.side_effect = [mock.mock_open(read_data=side_effect).return_value
+                           for side_effect in side_effects]
+  with mock.patch('__builtin__.open', mock_open):
+    return func(**kwargs), mock_open
+
+
+if __name__ == '__main__':
+  # Suppress logging messages.
+  unittest.main(buffer=True)
diff --git a/build/android/instr_action.gypi b/build/android/emma_instr_action.gypi
similarity index 74%
rename from build/android/instr_action.gypi
rename to build/android/emma_instr_action.gypi
index fa6d062..0505eab 100644
--- a/build/android/instr_action.gypi
+++ b/build/android/emma_instr_action.gypi
@@ -7,30 +7,23 @@
 
 {
   'variables': {
-    'instr_type%': 'jar',
     'input_path%': '',
     'output_path%': '',
     'stamp_path%': '',
     'extra_instr_args': [
-      '--coverage-file=<(_target_name).em',
-      '--sources-file=<(_target_name)_sources.txt',
+      '--coverage-file=<(coverage_file)',
+      '--sources-list-file=<(sources_list_file)',
     ],
     '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)',
+          '--source-dirs=<(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': 'instrument_jar',
       }, {
         'instr_action': 'copy',
         'extra_instr_args': [],
diff --git a/build/android/enable_asserts.py b/build/android/enable_asserts.py
index 8fb7dca..0616567 100755
--- a/build/android/enable_asserts.py
+++ b/build/android/enable_asserts.py
@@ -9,12 +9,15 @@
 import argparse
 import sys
 
-from pylib.device import device_utils
+from devil.android import device_blacklist
+from devil.android import device_utils
 
 
 def main():
   parser = argparse.ArgumentParser()
 
+  parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
+
   set_asserts_group = parser.add_mutually_exclusive_group(required=True)
   set_asserts_group.add_argument(
       '--enable_asserts', dest='set_asserts', action='store_true',
@@ -25,9 +28,14 @@
 
   args = parser.parse_args()
 
+  blacklist = (device_blacklist.Blacklist(args.blacklist_file)
+               if args.blacklist_file
+               else None)
+
   # TODO(jbudorick): Accept optional serial number and run only for the
   # specified device when present.
-  devices = device_utils.DeviceUtils.parallel()
+  devices = device_utils.DeviceUtils.parallel(
+      device_utils.DeviceUtils.HealthyDevices(blacklist))
 
   def set_java_asserts_and_restart(device):
     if device.SetJavaAsserts(args.set_asserts):
diff --git a/build/android/finalize_apk_action.gypi b/build/android/finalize_apk_action.gypi
index bdf9966..644f9e8 100644
--- a/build/android/finalize_apk_action.gypi
+++ b/build/android/finalize_apk_action.gypi
@@ -24,6 +24,7 @@
     'keystore_password%': 'chromium',
     'zipalign_path%': '<(android_sdk_tools)/zipalign',
     'rezip_apk_jar_path%': '<(PRODUCT_DIR)/lib.java/rezip_apk.jar',
+    'load_library_from_zip%': 0,
   },
   'inputs': [
     '<(DEPTH)/build/android/gyp/finalize_apk.py',
@@ -42,7 +43,7 @@
     '--key-path=<(keystore_path)',
     '--key-name=<(keystore_name)',
     '--key-passwd=<(keystore_password)',
-    '--load-library-from-zip-file=<(load_library_from_zip_file)',
+    '--load-library-from-zip=<(load_library_from_zip)',
     '--rezip-apk-jar-path=<(rezip_apk_jar_path)',
   ],
 }
diff --git a/build/android/finalize_splits_action.gypi b/build/android/finalize_splits_action.gypi
new file mode 100644
index 0000000..daa7f83
--- /dev/null
+++ b/build/android/finalize_splits_action.gypi
@@ -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.
+
+# This file is meant to be included into an action to provide an action that
+# signs and zipaligns split APKs.
+#
+# Required variables:
+#  apk_name - Base name of the apk.
+# Optional variables:
+#  density_splits - Whether to process density splits
+#  language_splits - Whether to language splits
+
+{
+  'variables': {
+    'keystore_path%': '<(DEPTH)/build/android/ant/chromium-debug.keystore',
+    'keystore_name%': 'chromiumdebugkey',
+    'keystore_password%': 'chromium',
+    'zipalign_path%': '<(android_sdk_tools)/zipalign',
+    'density_splits%': 0,
+    'language_splits%': [],
+    'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
+    'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
+    'base_output_path': '<(PRODUCT_DIR)/apks/<(apk_name)',
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/finalize_splits.py',
+    '<(DEPTH)/build/android/gyp/finalize_apk.py',
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(keystore_path)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/finalize_splits.py',
+    '--resource-packaged-apk-path=<(resource_packaged_apk_path)',
+    '--base-output-path=<(base_output_path)',
+    '--zipalign-path=<(zipalign_path)',
+    '--key-path=<(keystore_path)',
+    '--key-name=<(keystore_name)',
+    '--key-passwd=<(keystore_password)',
+  ],
+  'conditions': [
+    ['density_splits == 1', {
+      'message': 'Signing/aligning <(_target_name) density splits',
+      'inputs': [
+        '<(resource_packaged_apk_path)_hdpi',
+        '<(resource_packaged_apk_path)_xhdpi',
+        '<(resource_packaged_apk_path)_xxhdpi',
+        '<(resource_packaged_apk_path)_xxxhdpi',
+        '<(resource_packaged_apk_path)_tvdpi',
+      ],
+      'outputs': [
+        '<(base_output_path)-density-hdpi.apk',
+        '<(base_output_path)-density-xhdpi.apk',
+        '<(base_output_path)-density-xxhdpi.apk',
+        '<(base_output_path)-density-xxxhdpi.apk',
+        '<(base_output_path)-density-tvdpi.apk',
+      ],
+      'action': [
+        '--densities=hdpi,xhdpi,xxhdpi,xxxhdpi,tvdpi',
+      ],
+    }],
+    ['language_splits != []', {
+      'message': 'Signing/aligning <(_target_name) language splits',
+      'inputs': [
+        "<!@(python <(DEPTH)/build/apply_locales.py '<(resource_packaged_apk_path)_ZZLOCALE' <(language_splits))",
+      ],
+      'outputs': [
+        "<!@(python <(DEPTH)/build/apply_locales.py '<(base_output_path)-lang-ZZLOCALE.apk' <(language_splits))",
+      ],
+      'action': [
+        '--languages=<(language_splits)',
+      ],
+    }],
+  ],
+}
+
diff --git a/build/android/findbugs_action.gypi b/build/android/findbugs_action.gypi
deleted file mode 100644
index e3b3d36..0000000
--- a/build/android/findbugs_action.gypi
+++ /dev/null
@@ -1,22 +0,0 @@
-
-{
-  '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
index f55e462..d222e32 100755
--- a/build/android/findbugs_diff.py
+++ b/build/android/findbugs_diff.py
@@ -20,6 +20,7 @@
 import os
 import sys
 
+from devil.utils import run_tests_helper
 from pylib import constants
 from pylib.utils import findbugs
 
@@ -28,13 +29,15 @@
 
 sys.path.append(
     os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android', 'gyp'))
-from util import build_utils
+from util import build_utils # pylint: disable=import-error
 
 
 def main():
   parser = argparse.ArgumentParser()
 
   parser.add_argument(
+      '-v', '--verbose', action='count', help='Enable verbose logging.')
+  parser.add_argument(
       '-a', '--auxclasspath', default=None, dest='auxclasspath',
       help='Set aux classpath for analysis.')
   parser.add_argument(
@@ -69,6 +72,9 @@
       help='JAR file to analyze')
 
   args = parser.parse_args(build_utils.ExpandFileArgs(sys.argv[1:]))
+
+  run_tests_helper.SetLogLevel(args.verbose)
+
   if args.auxclasspath:
     args.auxclasspath = args.auxclasspath.split(':')
   elif args.auxclasspath_gyp:
diff --git a/build/android/findbugs_filter/findbugs_exclude.xml b/build/android/findbugs_filter/findbugs_exclude.xml
index dbff9d9..320a2bf 100644
--- a/build/android/findbugs_filter/findbugs_exclude.xml
+++ b/build/android/findbugs_filter/findbugs_exclude.xml
@@ -14,8 +14,9 @@
   <Match>
     <Class name="~.*\.R(\$\w+)?" />
   </Match>
+  <!-- Skip the generated Manifest class (including nested classes). -->
   <Match>
-    <Class name="~org\.chromium\..*\.Manifest(\$\w+)?" />
+    <Class name="~.*\.Manifest(\$\w+)?" />
   </Match>
   <Bug pattern="DM_STRING_CTOR" />
   <!-- Ignore "reliance on default String encoding" warnings, as we're not multi-platform -->
diff --git a/build/android/generate_emma_html.py b/build/android/generate_emma_html.py
index 93b0b0e..699abe5 100755
--- a/build/android/generate_emma_html.py
+++ b/build/android/generate_emma_html.py
@@ -12,7 +12,7 @@
 import os
 import sys
 
-from pylib import cmd_helper
+from devil.utils import cmd_helper
 from pylib import constants
 
 
diff --git a/build/android/gn/zip.py b/build/android/gn/zip.py
index 5050ea0..b80e0a1 100755
--- a/build/android/gn/zip.py
+++ b/build/android/gn/zip.py
@@ -11,16 +11,10 @@
 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)
@@ -37,7 +31,7 @@
   output = options.output
   base_dir = options.base_dir
 
-  DoZip(inputs, output, base_dir)
+  build_utils.DoZip(inputs, output, base_dir)
 
   if options.depfile:
     build_utils.WriteDepfile(
diff --git a/build/android/gyp/aidl.py b/build/android/gyp/aidl.py
index d5aa546..85ceeae 100755
--- a/build/android/gyp/aidl.py
+++ b/build/android/gyp/aidl.py
@@ -9,7 +9,9 @@
 
 import optparse
 import os
+import re
 import sys
+import zipfile
 
 from util import build_utils
 
@@ -42,7 +44,13 @@
       ]
       build_utils.CheckOutput(aidl_cmd)
 
-    build_utils.ZipDir(options.srcjar, temp_dir)
+    with zipfile.ZipFile(options.srcjar, 'w') as srcjar:
+      for path in build_utils.FindInDirectory(temp_dir, '*.java'):
+        with open(path) as fileobj:
+          data = fileobj.read()
+        pkg_name = re.search(r'^\s*package\s+(.*?)\s*;', data, re.M).group(1)
+        arcname = '%s/%s' % (pkg_name.replace('.', '/'), os.path.basename(path))
+        srcjar.writestr(arcname, data)
 
   if options.depfile:
     build_utils.WriteDepfile(
diff --git a/build/android/gyp/apk_install.py b/build/android/gyp/apk_install.py
index 419dc17..33697ca 100755
--- a/build/android/gyp/apk_install.py
+++ b/build/android/gyp/apk_install.py
@@ -20,17 +20,18 @@
 BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..')
 sys.path.append(BUILD_ANDROID_DIR)
 
+from devil.android import apk_helper
 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
+  # org.chromium.chrome.apk
   # -rw-r--r-- system   system    7376582 2013-04-19 16:34 \
-  # org.chromium.chrome.shell-1.apk
+  # org.chromium.chrome-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
@@ -62,6 +63,9 @@
       help='Path to .apk splits (can specify multiple times, causes '
       '--install-multiple to be used.',
       action='append')
+  parser.add_option('--android-sdk-tools',
+      help='Path to the Android SDK build tools folder. ' +
+           'Required when using --split-apk-path.')
   parser.add_option('--install-record',
       help='Path to install record (touched only when APK is installed).')
   parser.add_option('--build-device-configuration',
@@ -88,13 +92,10 @@
   # the build, then the APK has to be installed (regardless of the md5 record).
   force_install = HasInstallMetadataChanged(device, apk_package, metadata_path)
 
+
   def Install():
-    # TODO: Filter splits using split-select.
-    active_splits = options.split_apk_path
-    if active_splits:
-      device.adb.InstallMultiple(
-          [options.apk_path] + active_splits,
-          reinstall=True)
+    if options.split_apk_path:
+      device.InstallSplitApk(options.apk_path, options.split_apk_path)
     else:
       device.Install(options.apk_path, reinstall=True)
 
diff --git a/build/android/gyp/apk_obfuscate.py b/build/android/gyp/apk_obfuscate.py
index b075758..4a13cb1 100755
--- a/build/android/gyp/apk_obfuscate.py
+++ b/build/android/gyp/apk_obfuscate.py
@@ -10,14 +10,22 @@
 obfuscation will be a no-op.
 """
 
+import json
 import optparse
 import os
 import sys
+import tempfile
 
 from util import build_utils
 from util import proguard_util
 
 
+_PROGUARD_KEEP_CLASS = '''-keep class %s {
+  *;
+}
+'''
+
+
 def ParseArgs(argv):
   parser = optparse.OptionParser()
   parser.add_option('--android-sdk', help='path to the Android SDK folder')
@@ -35,6 +43,11 @@
 
   parser.add_option('--configuration-name',
                     help='Gyp configuration name (i.e. Debug, Release)')
+
+  parser.add_option('--debug-build-proguard-enabled', action='store_true',
+                    help='--proguard-enabled takes effect on release '
+                         'build, this flag enable the proguard on debug '
+                         'build.')
   parser.add_option('--proguard-enabled', action='store_true',
                     help='Set if proguard is enabled for this target.')
 
@@ -51,6 +64,12 @@
 
   parser.add_option('--stamp', help='File to touch on success')
 
+  parser.add_option('--main-dex-list-path',
+                    help='The list of classes to retain in the main dex. '
+                         'These will not be obfuscated.')
+  parser.add_option('--multidex-configuration-path',
+                    help='A JSON file containing multidex build configuration.')
+
   (options, args) = parser.parse_args(argv)
 
   if args:
@@ -80,7 +99,6 @@
   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 = []
@@ -89,29 +107,44 @@
     # 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.tested_apk_info(options.tested_apk_obfuscated_jar_path + '.info')
 
-    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.libraryjars([options.android_sdk_jar])
   proguard_injars = [p for p in input_jars if p not in exclude_paths]
   proguard.injars(proguard_injars)
-  proguard.configs(configs)
 
+  multidex_config = _PossibleMultidexConfig(options)
+  if multidex_config:
+    configs.append(multidex_config)
+
+  proguard.configs(configs)
   proguard.CheckOutput()
 
-  this_info = {
-    'inputs': proguard_injars,
-    'configs': configs
-  }
 
-  build_utils.WriteJson(
-      this_info, options.obfuscated_jar_path + '.info')
+def _PossibleMultidexConfig(options):
+  if not options.multidex_configuration_path:
+    return None
+
+  with open(options.multidex_configuration_path) as multidex_config_file:
+    multidex_config = json.loads(multidex_config_file.read())
+
+  if not (multidex_config.get('enabled') and options.main_dex_list_path):
+    return None
+
+  main_dex_list_config = ''
+  with open(options.main_dex_list_path) as main_dex_list:
+    for clazz in (l.strip() for l in main_dex_list):
+      if clazz.endswith('.class'):
+        clazz = clazz[:-len('.class')]
+      clazz = clazz.replace('/', '.')
+      main_dex_list_config += (_PROGUARD_KEEP_CLASS % clazz)
+  with tempfile.NamedTemporaryFile(
+      delete=False,
+      dir=os.path.dirname(options.main_dex_list_path),
+      prefix='main_dex_list_proguard',
+      suffix='.flags') as main_dex_config_file:
+    main_dex_config_file.write(main_dex_list_config)
+  return main_dex_config_file.name
 
 
 def main(argv):
@@ -125,7 +158,9 @@
     build_utils.MergeZips(
         options.test_jar_path, input_jars, dependency_class_filters)
 
-  if options.configuration_name == 'Release' and options.proguard_enabled:
+  if ((options.configuration_name == 'Release' and options.proguard_enabled) or
+     (options.configuration_name == 'Debug' and
+      options.debug_build_proguard_enabled)):
     DoProguard(options)
   else:
     output_files = [
diff --git a/build/android/gyp/apkbuilder.py b/build/android/gyp/apkbuilder.py
new file mode 100755
index 0000000..9e6b934
--- /dev/null
+++ b/build/android/gyp/apkbuilder.py
@@ -0,0 +1,254 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Adds the code parts to a resource APK."""
+
+import argparse
+import itertools
+import os
+import shutil
+import sys
+import zipfile
+
+from util import build_utils
+
+
+# Taken from aapt's Package.cpp:
+_NO_COMPRESS_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.gif', '.wav', '.mp2',
+                           '.mp3', '.ogg', '.aac', '.mpg', '.mpeg', '.mid',
+                           '.midi', '.smf', '.jet', '.rtttl', '.imy', '.xmf',
+                           '.mp4', '.m4a', '.m4v', '.3gp', '.3gpp', '.3g2',
+                           '.3gpp2', '.amr', '.awb', '.wma', '.wmv')
+
+
+def _ParseArgs(args):
+  parser = argparse.ArgumentParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_argument('--assets',
+                      help='GYP-list of files to add as assets in the form '
+                           '"srcPath:zipPath", where ":zipPath" is optional.',
+                      default='[]')
+  parser.add_argument('--write-asset-list',
+                      action='store_true',
+                      help='Whether to create an assets/assets_list file.')
+  parser.add_argument('--uncompressed-assets',
+                      help='Same as --assets, except disables compression.',
+                      default='[]')
+  parser.add_argument('--resource-apk',
+                      help='An .ap_ file built using aapt',
+                      required=True)
+  parser.add_argument('--output-apk',
+                      help='Path to the output file',
+                      required=True)
+  parser.add_argument('--dex-file',
+                      help='Path to the classes.dex to use')
+  parser.add_argument('--native-libs',
+                      action='append',
+                      help='GYP-list of native libraries to include. '
+                           'Can be specified multiple times.',
+                      default=[])
+  parser.add_argument('--android-abi',
+                      help='Android architecture to use for native libraries')
+  parser.add_argument('--native-lib-placeholders',
+                      help='GYP-list of native library placeholders to add.',
+                      default='[]')
+  parser.add_argument('--emma-device-jar',
+                      help='Path to emma_device.jar to include.')
+  options = parser.parse_args(args)
+  options.assets = build_utils.ParseGypList(options.assets)
+  options.uncompressed_assets = build_utils.ParseGypList(
+      options.uncompressed_assets)
+  options.native_lib_placeholders = build_utils.ParseGypList(
+      options.native_lib_placeholders)
+  all_libs = []
+  for gyp_list in options.native_libs:
+    all_libs.extend(build_utils.ParseGypList(gyp_list))
+  options.native_libs = all_libs
+
+  if not options.android_abi and (options.native_libs or
+                                  options.native_lib_placeholders):
+    raise Exception('Must specify --android-abi with --native-libs')
+  return options
+
+
+def _SplitAssetPath(path):
+  """Returns (src, dest) given an asset path in the form src[:dest]."""
+  path_parts = path.split(':')
+  src_path = path_parts[0]
+  if len(path_parts) > 1:
+    dest_path = path_parts[1]
+  else:
+    dest_path = os.path.basename(src_path)
+  return src_path, dest_path
+
+
+def _ExpandPaths(paths):
+  """Converts src:dst into tuples and enumerates files within directories.
+
+  Args:
+    paths: Paths in the form "src_path:dest_path"
+
+  Returns:
+    A list of (src_path, dest_path) tuples sorted by dest_path (for stable
+    ordering within output .apk).
+  """
+  ret = []
+  for path in paths:
+    src_path, dest_path = _SplitAssetPath(path)
+    if os.path.isdir(src_path):
+      for f in build_utils.FindInDirectory(src_path, '*'):
+        ret.append((f, os.path.join(dest_path, f[len(src_path) + 1:])))
+    else:
+      ret.append((src_path, dest_path))
+  ret.sort(key=lambda t:t[1])
+  return ret
+
+
+def _AddAssets(apk, path_tuples, disable_compression=False):
+  """Adds the given paths to the apk.
+
+  Args:
+    apk: ZipFile to write to.
+    paths: List of paths (with optional :zipPath suffix) to add.
+    disable_compression: Whether to disable compression.
+  """
+  # Group all uncompressed assets together in the hope that it will increase
+  # locality of mmap'ed files.
+  for target_compress in (False, True):
+    for src_path, dest_path in path_tuples:
+
+      compress = not disable_compression and (
+          os.path.splitext(src_path)[1] not in _NO_COMPRESS_EXTENSIONS)
+      if target_compress == compress:
+        apk_path = 'assets/' + dest_path
+        try:
+          apk.getinfo(apk_path)
+          # Should never happen since write_build_config.py handles merging.
+          raise Exception('Multiple targets specified the asset path: %s' %
+                          apk_path)
+        except KeyError:
+          build_utils.AddToZipHermetic(apk, apk_path, src_path=src_path,
+                                       compress=compress)
+
+
+def _CreateAssetsList(path_tuples):
+  """Returns a newline-separated list of asset paths for the given paths."""
+  dests = sorted(t[1] for t in path_tuples)
+  return '\n'.join(dests) + '\n'
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  options = _ParseArgs(args)
+
+  native_libs = sorted(options.native_libs)
+
+  input_paths = [options.resource_apk, __file__] + native_libs
+  if options.dex_file:
+    input_paths.append(options.dex_file)
+
+  if options.emma_device_jar:
+    input_paths.append(options.emma_device_jar)
+
+  input_strings = [options.android_abi, options.native_lib_placeholders]
+
+  _assets = _ExpandPaths(options.assets)
+  _uncompressed_assets = _ExpandPaths(options.uncompressed_assets)
+
+  for src_path, dest_path in itertools.chain(_assets, _uncompressed_assets):
+    input_paths.append(src_path)
+    input_strings.append(dest_path)
+
+  def on_stale_md5():
+    tmp_apk = options.output_apk + '.tmp'
+    try:
+      # TODO(agrieve): It would be more efficient to combine this step
+      # with finalize_apk(), which sometimes aligns and uncompresses the
+      # native libraries.
+      with zipfile.ZipFile(options.resource_apk) as resource_apk, \
+           zipfile.ZipFile(tmp_apk, 'w', zipfile.ZIP_DEFLATED) as out_apk:
+        def copy_resource(zipinfo):
+          compress = zipinfo.compress_type != zipfile.ZIP_STORED
+          build_utils.AddToZipHermetic(out_apk, zipinfo.filename,
+                                       data=resource_apk.read(zipinfo.filename),
+                                       compress=compress)
+
+        # Make assets come before resources in order to maintain the same file
+        # ordering as GYP / aapt. http://crbug.com/561862
+        resource_infos = resource_apk.infolist()
+
+        # 1. AndroidManifest.xml
+        assert resource_infos[0].filename == 'AndroidManifest.xml'
+        copy_resource(resource_infos[0])
+
+        # 2. Assets
+        if options.write_asset_list:
+          data = _CreateAssetsList(
+              itertools.chain(_assets, _uncompressed_assets))
+          build_utils.AddToZipHermetic(out_apk, 'assets/assets_list', data=data)
+
+        _AddAssets(out_apk, _assets, disable_compression=False)
+        _AddAssets(out_apk, _uncompressed_assets, disable_compression=True)
+
+        # 3. Resources
+        for info in resource_infos[1:]:
+          copy_resource(info)
+
+        # 4. Dex files
+        if options.dex_file and options.dex_file.endswith('.zip'):
+          with zipfile.ZipFile(options.dex_file, 'r') as dex_zip:
+            for dex in (d for d in dex_zip.namelist() if d.endswith('.dex')):
+              build_utils.AddToZipHermetic(out_apk, dex, data=dex_zip.read(dex))
+        elif options.dex_file:
+          build_utils.AddToZipHermetic(out_apk, 'classes.dex',
+                                       src_path=options.dex_file)
+
+        # 5. Native libraries.
+        for path in native_libs:
+          basename = os.path.basename(path)
+          apk_path = 'lib/%s/%s' % (options.android_abi, basename)
+          build_utils.AddToZipHermetic(out_apk, apk_path, src_path=path)
+
+        for name in sorted(options.native_lib_placeholders):
+          # Make it non-empty so that its checksum is non-zero and is not
+          # ignored by md5_check.
+          apk_path = 'lib/%s/%s.so' % (options.android_abi, name)
+          build_utils.AddToZipHermetic(out_apk, apk_path, data=':)')
+
+        # 6. Java resources. Used only when coverage is enabled, so order
+        # doesn't matter).
+        if options.emma_device_jar:
+          # Add EMMA Java resources to APK.
+          with zipfile.ZipFile(options.emma_device_jar, 'r') as emma_device_jar:
+            for apk_path in emma_device_jar.namelist():
+              apk_path_lower = apk_path.lower()
+              if apk_path_lower.startswith('meta-inf/'):
+                continue
+
+              if apk_path_lower.endswith('/'):
+                continue
+
+              if apk_path_lower.endswith('.class'):
+                continue
+
+              build_utils.AddToZipHermetic(out_apk, apk_path,
+                                           data=emma_device_jar.read(apk_path))
+
+      shutil.move(tmp_apk, options.output_apk)
+    finally:
+      if os.path.exists(tmp_apk):
+        os.unlink(tmp_apk)
+
+  build_utils.CallAndWriteDepfileIfStale(
+      on_stale_md5,
+      options,
+      input_paths=input_paths,
+      input_strings=input_strings,
+      output_paths=[options.output_apk])
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/build/android/gyp/configure_multidex.py b/build/android/gyp/configure_multidex.py
new file mode 100755
index 0000000..aa85d2f
--- /dev/null
+++ b/build/android/gyp/configure_multidex.py
@@ -0,0 +1,55 @@
+#!/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 argparse
+import json
+import sys
+
+from util import build_utils
+
+
+def ParseArgs():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--configuration-name', required=True,
+                      help='The build CONFIGURATION_NAME.')
+  parser.add_argument('--enabled-configurations', default=[],
+                      help='The configuration(s) for which multidex should be '
+                           'enabled. If not specified and --enable-multidex is '
+                           'passed, multidex will be enabled for all '
+                            'configurations.')
+  parser.add_argument('--multidex-configuration-path', required=True,
+                      help='The path to which the multidex configuration JSON '
+                           'should be saved.')
+
+  args = parser.parse_args()
+
+  if args.enabled_configurations:
+    args.enabled_configurations = build_utils.ParseGypList(
+        args.enabled_configurations)
+
+  return args
+
+
+def main():
+  args = ParseArgs()
+
+  multidex_enabled = (
+      (not args.enabled_configurations
+       or args.configuration_name in args.enabled_configurations))
+
+  config = {
+    'enabled': multidex_enabled,
+  }
+
+  with open(args.multidex_configuration_path, 'w') as f:
+    f.write(json.dumps(config))
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
+
diff --git a/build/android/gyp/copy_ex.py b/build/android/gyp/copy_ex.py
index a474e77..3d7434d 100755
--- a/build/android/gyp/copy_ex.py
+++ b/build/android/gyp/copy_ex.py
@@ -6,6 +6,7 @@
 
 """Copies files to a directory."""
 
+import itertools
 import optparse
 import os
 import shutil
@@ -23,6 +24,47 @@
     result.extend([os.path.join(root[len(dirname):], f) for f in files])
   return result
 
+def CopyFile(f, dest, deps):
+  """Copy file or directory and update deps."""
+  if os.path.isdir(f):
+    shutil.copytree(f, os.path.join(dest, os.path.basename(f)))
+    deps.extend(_get_all_files(f))
+  else:
+    shutil.copy(f, dest)
+    deps.append(f)
+
+def DoCopy(options, deps):
+  """Copy files or directories given in options.files and update deps."""
+  files = list(itertools.chain.from_iterable(build_utils.ParseGypList(f)
+                                             for f in options.files))
+
+  for f in files:
+    if os.path.isdir(f) and not options.clear:
+      print ('To avoid stale files you must use --clear when copying '
+             'directories')
+      sys.exit(-1)
+    CopyFile(f, options.dest, deps)
+
+def DoRenaming(options, deps):
+  """Copy and rename files given in options.renaming_sources and update deps."""
+  src_files = list(itertools.chain.from_iterable(
+                   build_utils.ParseGypList(f)
+                   for f in options.renaming_sources))
+
+  dest_files = list(itertools.chain.from_iterable(
+                    build_utils.ParseGypList(f)
+                    for f in options.renaming_destinations))
+
+  if (len(src_files) != len(dest_files)):
+    print('Renaming source and destination files not match.')
+    sys.exit(-1)
+
+  for src, dest in itertools.izip(src_files, dest_files):
+    if os.path.isdir(src):
+      print ('renaming diretory is not supported.')
+      sys.exit(-1)
+    else:
+      CopyFile(src, os.path.join(options.dest, dest), deps)
 
 def main(args):
   args = build_utils.ExpandFileArgs(args)
@@ -38,6 +80,14 @@
                     '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.')
+  parser.add_option('--renaming-sources',
+                    action='append',
+                    help='List of files need to be renamed while being '
+                         'copied to dest directory')
+  parser.add_option('--renaming-destinations',
+                    action='append',
+                    help='List of destination file name without path, the '
+                         'number of elements must match rename-sources.')
 
   options, _ = parser.parse_args(args)
 
@@ -45,23 +95,13 @@
     build_utils.DeleteDirectory(options.dest)
     build_utils.MakeDirectory(options.dest)
 
-  files = []
-  for file_arg in options.files:
-    files += build_utils.ParseGypList(file_arg)
-
   deps = []
 
-  for f in files:
-    if os.path.isdir(f):
-      if not options.clear:
-        print ('To avoid stale files you must use --clear when copying '
-               'directories')
-        sys.exit(-1)
-      shutil.copytree(f, os.path.join(options.dest, os.path.basename(f)))
-      deps.extend(_get_all_files(f))
-    else:
-      shutil.copy(f, options.dest)
-      deps.append(f)
+  if options.files:
+    DoCopy(options, deps)
+
+  if options.renaming_sources:
+    DoRenaming(options, deps)
 
   if options.depfile:
     build_utils.WriteDepfile(
diff --git a/build/android/gyp/create_device_library_links.py b/build/android/gyp/create_device_library_links.py
index 3e630b6..8c155a0 100755
--- a/build/android/gyp/create_device_library_links.py
+++ b/build/android/gyp/create_device_library_links.py
@@ -21,8 +21,8 @@
 BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..')
 sys.path.append(BUILD_ANDROID_DIR)
 
+from devil.android import apk_helper
 from pylib import constants
-from pylib.utils import apk_helper
 
 def RunShellCommand(device, cmd):
   output = device.RunShellCommand(cmd)
diff --git a/build/android/gyp/create_java_binary_script.py b/build/android/gyp/create_java_binary_script.py
index d632728..721e96f 100755
--- a/build/android/gyp/create_java_binary_script.py
+++ b/build/android/gyp/create_java_binary_script.py
@@ -30,14 +30,20 @@
 
 self_dir = os.path.dirname(__file__)
 classpath = [{classpath}]
+bootclasspath = [{bootclasspath}]
+extra_program_args = {extra_program_args}
 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)
+  bootclasspath = [os.path.join(offset, p) for p in bootclasspath]
+java_cmd = ["java"]
+if bootclasspath:
+    java_cmd.append("-Xbootclasspath/p:" + ":".join(bootclasspath))
+java_cmd.extend(
+    ["-classpath", ":".join(classpath), "-enableassertions", \"{main_class}\"])
+java_cmd.extend(extra_program_args)
+java_cmd.extend(sys.argv[1:])
+os.execvp("java", java_cmd)
 """
 
 def main(argv):
@@ -48,21 +54,31 @@
   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',
+  parser.add_option('--classpath', action='append', default=[],
       help='Classpath for running the jar.')
-  options, _ = parser.parse_args(argv)
+  parser.add_option('--bootclasspath', action='append', default=[],
+      help='zip/jar files to add to bootclasspath for java cmd.')
+  options, extra_program_args = parser.parse_args(argv)
 
   classpath = [options.jar_path]
   for cp_arg in options.classpath:
     classpath += build_utils.ParseGypList(cp_arg)
 
+  bootclasspath = []
+  for bootcp_arg in options.bootclasspath:
+    bootclasspath += build_utils.ParseGypList(bootcp_arg)
+
   run_dir = os.path.dirname(options.output)
+  bootclasspath = [os.path.relpath(p, run_dir) for p in bootclasspath]
   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))
+      bootclasspath=('"%s"' % '", "'.join(bootclasspath)
+                     if bootclasspath else ''),
+      main_class=options.main_class,
+      extra_program_args=repr(extra_program_args)))
 
   os.chmod(options.output, 0750)
 
diff --git a/build/android/gyp/create_test_runner_script.py b/build/android/gyp/create_test_runner_script.py
new file mode 100755
index 0000000..e5e5653
--- /dev/null
+++ b/build/android/gyp/create_test_runner_script.py
@@ -0,0 +1,100 @@
+#!/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.
+
+"""Creates a script to run an android test using build/android/test_runner.py.
+"""
+
+import argparse
+import os
+import sys
+
+from util import build_utils
+
+SCRIPT_TEMPLATE = """\
+#!/usr/bin/env python
+#
+# This file was generated by build/android/gyp/create_test_runner_script.py
+
+import os
+import subprocess
+import sys
+
+def main():
+  script_directory = os.path.dirname(__file__)
+
+  def ResolvePath(path):
+    \"\"\"Returns an absolute filepath given a path relative to this script.
+    \"\"\"
+    return os.path.abspath(os.path.join(script_directory, path))
+
+  test_runner_path = ResolvePath('{test_runner_path}')
+  test_runner_args = {test_runner_args}
+  test_runner_path_args = {test_runner_path_args}
+  for arg, path in sorted(test_runner_path_args.iteritems()):
+    test_runner_args.extend([arg, ResolvePath(path)])
+
+  test_runner_cmd = [test_runner_path] + test_runner_args + sys.argv[1:]
+  print ' '.join(test_runner_cmd)
+  return subprocess.call(test_runner_cmd)
+
+if __name__ == '__main__':
+  sys.exit(main())
+"""
+
+def main(args):
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--script-output-path',
+                      help='Output path for executable script.')
+  parser.add_argument('--depfile',
+                      help='Path to the depfile. This must be specified as '
+                           "the action's first output.")
+  # We need to intercept any test runner path arguments and make all
+  # of the paths relative to the output script directory.
+  group = parser.add_argument_group('Test runner path arguments.')
+  group.add_argument('--output-directory')
+  group.add_argument('--isolate-file-path')
+  group.add_argument('--apk-under-test')
+  group.add_argument('--test-apk')
+  args, test_runner_args = parser.parse_known_args(
+      build_utils.ExpandFileArgs(args))
+
+  def RelativizePathToScript(path):
+    """Returns the path relative to the output script directory."""
+    return os.path.relpath(path, os.path.dirname(args.script_output_path))
+
+  test_runner_path = os.path.join(
+      os.path.dirname(__file__), os.path.pardir, 'test_runner.py')
+  test_runner_path = RelativizePathToScript(test_runner_path)
+
+  test_runner_path_args = {}
+  if args.output_directory:
+    test_runner_path_args['--output-directory'] = RelativizePathToScript(
+        args.output_directory)
+  if args.isolate_file_path:
+    test_runner_path_args['--isolate-file-path'] = RelativizePathToScript(
+        args.isolate_file_path)
+  if args.apk_under_test:
+    test_runner_path_args['--apk-under-test'] = RelativizePathToScript(
+        args.apk_under_test)
+  if args.test_apk:
+    test_runner_path_args['--test-apk'] = RelativizePathToScript(
+        args.test_apk)
+
+  with open(args.script_output_path, 'w') as script:
+    script.write(SCRIPT_TEMPLATE.format(
+        test_runner_path=str(test_runner_path),
+        test_runner_args=str(test_runner_args),
+        test_runner_path_args=str(test_runner_path_args)))
+
+  os.chmod(args.script_output_path, 0750)
+
+  if args.depfile:
+    build_utils.WriteDepfile(
+        args.depfile,
+        build_utils.GetPythonDependencies())
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py
index 4e62332..d903269 100755
--- a/build/android/gyp/dex.py
+++ b/build/android/gyp/dex.py
@@ -4,79 +4,192 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import json
+import logging
 import optparse
 import os
 import sys
+import tempfile
+import zipfile
 
 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 _RemoveUnwantedFilesFromZip(dex_path):
+  iz = zipfile.ZipFile(dex_path, 'r')
+  tmp_dex_path = '%s.tmp.zip' % dex_path
+  oz = zipfile.ZipFile(tmp_dex_path, 'w', zipfile.ZIP_DEFLATED)
+  for i in iz.namelist():
+    if i.endswith('.dex'):
+      oz.writestr(i, iz.read(i))
+  os.remove(dex_path)
+  os.rename(tmp_dex_path, dex_path)
 
 
-def main():
-  args = build_utils.ExpandFileArgs(sys.argv[1:])
+def _ParseArgs(args):
+  args = build_utils.ExpandFileArgs(args)
 
   parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
 
   parser.add_option('--android-sdk-tools',
                     help='Android sdk build tools directory.')
+  parser.add_option('--output-directory',
+                    default=os.getcwd(),
+                    help='Path to the output build 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('--debug-build-proguard-enabled',
+                    help='"true" if proguard is enabled for debug build.')
   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('--incremental',
+                    action='store_true',
+                    help='Enable incremental builds when possible.')
   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.')
+  parser.add_option('--main-dex-list-path',
+                    help='A file containing a list of the classes to '
+                         'include in the main dex.')
+  parser.add_option('--multidex-configuration-path',
+                    help='A JSON file containing multidex build configuration.')
+  parser.add_option('--multi-dex', default=False, action='store_true',
+                    help='Generate multiple dex files.')
 
   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'):
+  if options.multidex_configuration_path:
+    with open(options.multidex_configuration_path) as multidex_config_file:
+      multidex_config = json.loads(multidex_config_file.read())
+    options.multi_dex = multidex_config.get('enabled', False)
+
+  if options.multi_dex and not options.main_dex_list_path:
+    logging.warning('multidex cannot be enabled without --main-dex-list-path')
+    options.multi_dex = False
+  elif options.main_dex_list_path and not options.multi_dex:
+    logging.warning('--main-dex-list-path is unused if multidex is not enabled')
+
+  if options.inputs:
+    options.inputs = build_utils.ParseGypList(options.inputs)
+  if options.excluded_paths:
+    options.excluded_paths = build_utils.ParseGypList(options.excluded_paths)
+
+  return options, paths
+
+
+def _AllSubpathsAreClassFiles(paths, changes):
+  for path in paths:
+    if any(not p.endswith('.class') for p in changes.IterChangedSubpaths(path)):
+      return False
+  return True
+
+
+def _RunDx(changes, options, dex_cmd, paths):
+  with build_utils.TempDir() as classes_temp_dir:
+    # --multi-dex is incompatible with --incremental.
+    if options.multi_dex:
+      dex_cmd.append('--main-dex-list=%s' % options.main_dex_list_path)
+    else:
+      # Use --incremental when .class files are added or modified (never when
+      # removed).
+      # --incremental tells dx to merge all newly dex'ed .class files with
+      # what that already exist in the output dex file (existing classes are
+      # replaced).
+      if options.incremental and changes.AddedOrModifiedOnly():
+        changed_inputs = set(changes.IterChangedPaths())
+        changed_paths = [p for p in paths if p in changed_inputs]
+        if not changed_paths:
+          return
+        # When merging in other dex files, there's no easy way to know if
+        # classes were removed from them.
+        if _AllSubpathsAreClassFiles(changed_paths, changes):
+          dex_cmd.append('--incremental')
+          for path in changed_paths:
+            changed_subpaths = set(changes.IterChangedSubpaths(path))
+            # Not a fundamental restriction, but it's the case right now and it
+            # simplifies the logic to assume so.
+            assert changed_subpaths, 'All inputs should be zip files.'
+            build_utils.ExtractAll(path, path=classes_temp_dir,
+                                   predicate=lambda p: p in changed_subpaths)
+          paths = [classes_temp_dir]
+
+    dex_cmd += paths
+    build_utils.CheckOutput(dex_cmd, print_stderr=False)
+
+  if options.dex_path.endswith('.zip'):
+    _RemoveUnwantedFilesFromZip(options.dex_path)
+
+
+def _OnStaleMd5(changes, options, dex_cmd, paths):
+  _RunDx(changes, options, dex_cmd, paths)
+  build_utils.WriteJson(
+      [os.path.relpath(p, options.output_directory) for p in paths],
+      options.dex_path + '.inputs')
+
+
+def main(args):
+  options, paths = _ParseArgs(args)
+  if ((options.proguard_enabled == 'true'
+          and options.configuration_name == 'Release')
+      or (options.debug_build_proguard_enabled == 'true'
+          and options.configuration_name == 'Debug')):
     paths = [options.proguard_enabled_input_path]
 
   if options.inputs:
-    paths += build_utils.ParseGypList(options.inputs)
+    paths += 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]
+    # Excluded paths are relative to the output directory.
+    exclude_paths = options.excluded_paths
+    paths = [p for p in paths if not
+             os.path.relpath(p, options.output_directory) in exclude_paths]
 
-  DoDex(options, paths)
+  input_paths = list(paths)
 
-  if options.depfile:
-    build_utils.WriteDepfile(
-        options.depfile,
-        paths + build_utils.GetPythonDependencies())
+  dx_binary = os.path.join(options.android_sdk_tools, 'dx')
+  # See http://crbug.com/272064 for context on --force-jumbo.
+  # See https://github.com/android/platform_dalvik/commit/dd140a22d for
+  # --num-threads.
+  dex_cmd = [dx_binary, '--num-threads=8', '--dex', '--force-jumbo',
+             '--output', options.dex_path]
+  if options.no_locals != '0':
+    dex_cmd.append('--no-locals')
 
+  if options.multi_dex:
+    input_paths.append(options.main_dex_list_path)
+    dex_cmd += [
+      '--multi-dex',
+      '--minimal-main-dex',
+    ]
+
+  output_paths = [
+    options.dex_path,
+    options.dex_path + '.inputs',
+  ]
+
+  # An escape hatch to be able to check if incremental dexing is causing
+  # problems.
+  force = int(os.environ.get('DISABLE_INCREMENTAL_DX', 0))
+
+  build_utils.CallAndWriteDepfileIfStale(
+      lambda changes: _OnStaleMd5(changes, options, dex_cmd, paths),
+      options,
+      input_paths=input_paths,
+      input_strings=dex_cmd,
+      output_paths=output_paths,
+      force=force,
+      pass_changes=True)
 
 
 if __name__ == '__main__':
-  sys.exit(main())
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/emma_instr.py b/build/android/gyp/emma_instr.py
index 6f3555a..c6ef618 100755
--- a/build/android/gyp/emma_instr.py
+++ b/build/android/gyp/emma_instr.py
@@ -8,12 +8,10 @@
 
 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.
+call the instrument command 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.
@@ -34,6 +32,7 @@
 
 def _AddCommonOptions(option_parser):
   """Adds common options to |option_parser|."""
+  build_utils.AddDepfileOption(option_parser)
   option_parser.add_option('--input-path',
                            help=('Path to input file(s). Either the classes '
                                  'directory, or the path to a jar.'))
@@ -44,15 +43,21 @@
   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',
+  option_parser.add_option('--sources-list-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('--source-dirs',
+                           help='Space separated list of source directories. '
+                                'source-files should not be specified if '
+                                'source-dirs is specified')
+  option_parser.add_option('--source-files',
+                           help='Space separated list of source files. '
+                                'source-dirs should not be specified if '
+                                'source-files is specified')
   option_parser.add_option('--src-root',
                            help='Root of the src repository.')
   option_parser.add_option('--emma-jar',
@@ -79,43 +84,52 @@
     An exit code.
   """
   if not (options.input_path and options.output_path and
-          options.coverage_file and options.sources_file):
+          options.coverage_file and options.sources_list_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.exists(options.coverage_file):
+    os.remove(options.coverage_file)
+  if os.path.exists(options.sources_list_file):
+    os.remove(options.sources_list_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)
+  shutil.copy(options.input_path, options.output_path)
 
   if options.stamp:
     build_utils.Touch(options.stamp)
 
+  if options.depfile:
+    build_utils.WriteDepfile(options.depfile,
+                             build_utils.GetPythonDependencies())
 
-def _CreateSourcesFile(sources_string, sources_file, src_root):
-  """Adds all normalized source directories to |sources_file|.
+
+def _GetSourceDirsFromSourceFiles(source_files_string):
+  """Returns list of directories for the files in |source_files_string|.
 
   Args:
-    sources_string: String generated from gyp containing the list of sources.
-    sources_file: File into which to write the JSON list of sources.
+    source_files_string: String generated from GN or GYP containing the list
+      of source files.
+
+  Returns:
+    List of source directories.
+  """
+  source_files = build_utils.ParseGypList(source_files_string)
+  return list(set(os.path.dirname(source_file) for source_file in source_files))
+
+
+def _CreateSourcesListFile(source_dirs, sources_list_file, src_root):
+  """Adds all normalized source directories to |sources_list_file|.
+
+  Args:
+    source_dirs: List of source directories.
+    sources_list_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:
+  for s in source_dirs:
     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'
@@ -125,17 +139,16 @@
 
     relative_sources.append(rel_source)
 
-  with open(sources_file, 'w') as f:
+  with open(sources_list_file, 'w') as f:
     json.dump(relative_sources, f)
 
 
-def _RunInstrumentCommand(command, options, _, option_parser):
-  """Instruments the classes/jar files using EMMA.
+def _RunInstrumentCommand(_command, options, _, option_parser):
+  """Instruments 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.
+    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.
@@ -144,16 +157,13 @@
     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.coverage_file and options.sources_list_file and
+          (options.source_files or options.source_dirs) 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)
+  if os.path.exists(options.coverage_file):
+    os.remove(options.coverage_file)
   temp_dir = tempfile.mkdtemp()
   try:
     cmd = ['java', '-cp', options.emma_jar,
@@ -161,27 +171,34 @@
            '-ip', options.input_path,
            '-ix', options.filter_string,
            '-d', temp_dir,
-           '-out', coverage_file,
+           '-out', options.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)
+    temp_jar_dir = os.path.join(temp_dir, 'lib')
+    jars = os.listdir(temp_jar_dir)
+    if len(jars) != 1:
+      print('Error: multiple output files in: %s' % (temp_jar_dir))
+      return 1
+
+    shutil.copy(os.path.join(temp_jar_dir, jars[0]), options.output_path)
   finally:
     shutil.rmtree(temp_dir)
 
-  _CreateSourcesFile(options.sources, sources_file, options.src_root)
+  if options.source_dirs:
+    source_dirs = build_utils.ParseGypList(options.source_dirs)
+  else:
+    source_dirs = _GetSourceDirsFromSourceFiles(options.source_files)
+  _CreateSourcesListFile(source_dirs, options.sources_list_file,
+                         options.src_root)
 
   if options.stamp:
     build_utils.Touch(options.stamp)
 
+  if options.depfile:
+    build_utils.WriteDepfile(options.depfile,
+                             build_utils.GetPythonDependencies())
+
   return 0
 
 
@@ -192,8 +209,6 @@
                                  _RunCopyCommand),
     'instrument_jar': CommandFunctionTuple(_AddInstrumentOptions,
                                            _RunInstrumentCommand),
-    'instrument_classes': CommandFunctionTuple(_AddInstrumentOptions,
-                                               _RunInstrumentCommand),
 }
 
 
diff --git a/build/android/gyp/finalize_apk.py b/build/android/gyp/finalize_apk.py
index 5416008..a6a1040 100755
--- a/build/android/gyp/finalize_apk.py
+++ b/build/android/gyp/finalize_apk.py
@@ -65,7 +65,9 @@
   build_utils.CheckOutput(align_cmd)
 
 
-def main():
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+
   parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
 
@@ -79,17 +81,41 @@
   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',
+  parser.add_option('--load-library-from-zip', 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()
 
+  input_paths = [
+    options.unsigned_apk_path,
+    options.key_path,
+  ]
+
+  if options.load_library_from_zip:
+    input_paths.append(options.rezip_apk_jar_path)
+
+  input_strings = [
+    options.load_library_from_zip,
+    options.key_name,
+    options.key_passwd,
+  ]
+
+  build_utils.CallAndWriteDepfileIfStale(
+      lambda: FinalizeApk(options),
+      options,
+      record_path=options.unsigned_apk_path + '.finalize.md5.stamp',
+      input_paths=input_paths,
+      input_strings=input_strings,
+      output_paths=[options.final_apk_path])
+
+
+def FinalizeApk(options):
   with tempfile.NamedTemporaryFile() as signed_apk_path_tmp, \
       tempfile.NamedTemporaryFile() as apk_to_sign_tmp:
 
-    if options.load_library_from_zip_file:
+    if options.load_library_from_zip:
       # 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
@@ -106,7 +132,7 @@
     JarSigner(options.key_path, options.key_name, options.key_passwd,
               apk_to_sign, signed_apk_path)
 
-    if options.load_library_from_zip_file:
+    if options.load_library_from_zip:
       # 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.
@@ -116,13 +142,6 @@
       # 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())
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/finalize_splits.py b/build/android/gyp/finalize_splits.py
new file mode 100755
index 0000000..a6796bb
--- /dev/null
+++ b/build/android/gyp/finalize_splits.py
@@ -0,0 +1,52 @@
+#!/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.
+"""Signs and zipaligns split APKs.
+
+This script is require only by GYP (not GN).
+"""
+
+import optparse
+import sys
+
+import finalize_apk
+from util import build_utils
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('--zipalign-path', help='Path to the zipalign tool.')
+  parser.add_option('--resource-packaged-apk-path',
+      help='Base path to input .ap_s.')
+  parser.add_option('--base-output-path',
+      help='Path to output .apk, minus extension.')
+  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('--densities',
+      help='Comma separated list of densities finalize.')
+  parser.add_option('--languages',
+      help='GYP list of language splits to finalize.')
+
+  options, _ = parser.parse_args()
+  options.load_library_from_zip = 0
+
+  if options.densities:
+    for density in options.densities.split(','):
+      options.unsigned_apk_path = ("%s_%s" %
+          (options.resource_packaged_apk_path, density))
+      options.final_apk_path = ("%s-density-%s.apk" %
+          (options.base_output_path, density))
+      finalize_apk.FinalizeApk(options)
+
+  if options.languages:
+    for lang in build_utils.ParseGypList(options.languages):
+      options.unsigned_apk_path = ("%s_%s" %
+          (options.resource_packaged_apk_path, lang))
+      options.final_apk_path = ("%s-lang-%s.apk" %
+          (options.base_output_path, lang))
+      finalize_apk.FinalizeApk(options)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/find_sun_tools_jar.py b/build/android/gyp/find_sun_tools_jar.py
new file mode 100755
index 0000000..2f15a15
--- /dev/null
+++ b/build/android/gyp/find_sun_tools_jar.py
@@ -0,0 +1,56 @@
+#!/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 finds the java distribution's tools.jar and copies it somewhere.
+"""
+
+import argparse
+import os
+import re
+import shutil
+import sys
+
+from util import build_utils
+
+RT_JAR_FINDER = re.compile(r'\[Opened (.*)/jre/lib/rt.jar\]')
+
+def main():
+  parser = argparse.ArgumentParser(description='Find Sun Tools Jar')
+  parser.add_argument('--depfile',
+                      help='Path to depfile. This must be specified as the '
+                           'action\'s first output.')
+  parser.add_argument('--output', required=True)
+  args = parser.parse_args()
+
+  sun_tools_jar_path = FindSunToolsJarPath()
+
+  if sun_tools_jar_path is None:
+    raise Exception("Couldn\'t find tools.jar")
+
+  # Using copyfile instead of copy() because copy() calls copymode()
+  # We don't want the locked mode because we may copy over this file again
+  shutil.copyfile(sun_tools_jar_path, args.output)
+
+  if args.depfile:
+    build_utils.WriteDepfile(
+        args.depfile,
+        [sun_tools_jar_path] + build_utils.GetPythonDependencies())
+
+
+def FindSunToolsJarPath():
+  # This works with at least openjdk 1.6, 1.7 and sun java 1.6, 1.7
+  stdout = build_utils.CheckOutput(
+      ["java", "-verbose", "-version"], print_stderr=False)
+  for ln in stdout.splitlines():
+    match = RT_JAR_FINDER.match(ln)
+    if match:
+      return os.path.join(match.group(1), 'lib', 'tools.jar')
+
+  return None
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/generate_copy_ex_outputs.py b/build/android/gyp/generate_copy_ex_outputs.py
new file mode 100755
index 0000000..e425b4a
--- /dev/null
+++ b/build/android/gyp/generate_copy_ex_outputs.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+# Generate outputs according source files and destination path for
+# copy_ex.gypi
+
+import argparse
+import os
+import sys
+
+def DoMain(argv):
+  parser = argparse.ArgumentParser(prog='generate_copy_ex_outputs')
+  parser.add_argument('--src-files',
+                      nargs = '+',
+                      help = 'a list of files to copy')
+  parser.add_argument('--dest-path',
+                      required = True,
+                      help = 'the directory to copy file to')
+  options = parser.parse_args(argv)
+  # Quote each element so filename spaces don't mess up gyp's attempt to parse
+  # it into a list.
+  return ' '.join('"%s"' % os.path.join(options.dest_path,
+                                        os.path.basename(src))
+                  for src in options.src_files)
+
+if __name__ == '__main__':
+  results = DoMain(sys.argv[1:])
+  if results:
+    print results
+
diff --git a/build/android/gyp/generate_resource_rewriter.py b/build/android/gyp/generate_resource_rewriter.py
new file mode 100755
index 0000000..b6202ed
--- /dev/null
+++ b/build/android/gyp/generate_resource_rewriter.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Generate ResourceRewriter.java which overwrites the given package's
+   resource id.
+"""
+
+import argparse
+import os
+import sys
+import zipfile
+
+from util import build_utils
+
+# Import jinja2 from third_party/jinja2
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),
+                                             '..',
+                                             '..',
+                                             '..',
+                                             'third_party')))
+import jinja2
+
+
+RESOURCE_REWRITER_JAVA="ResourceRewriter.java"
+
+RESOURCE_REWRITER="""/* AUTO-GENERATED FILE.  DO NOT MODIFY. */
+
+package {{ package }};
+/**
+ * Helper class used to fix up resource ids.
+ */
+class ResourceRewriter {
+    /**
+     * Rewrite the R 'constants' for the WebView.
+     */
+    public static void rewriteRValues(final int packageId) {
+        {% for res_package in res_packages %}
+        {{ res_package }}.R.onResourcesLoaded(packageId);
+        {% endfor %}
+    }
+}
+"""
+
+def ParseArgs(args):
+  """Parses command line options.
+
+  Returns:
+    An Namespace from argparse.parse_args()
+  """
+  parser = argparse.ArgumentParser(prog='generate_resource_rewriter')
+
+  parser.add_argument('--package-name',
+                      required=True,
+                      help='The package name of ResourceRewriter.')
+  parser.add_argument('--dep-packages',
+                      required=True,
+                      help='A list of packages whose resource id will be'
+                           'overwritten in ResourceRewriter.')
+  parser.add_argument('--output-dir',
+                      help='A output directory of generated'
+                           ' ResourceRewriter.java')
+  parser.add_argument('--srcjar',
+                      help='The path of generated srcjar which has'
+                           ' ResourceRewriter.java')
+
+  return parser.parse_args(args)
+
+
+def CreateResourceRewriter(package, res_packages, output_dir):
+  build_utils.MakeDirectory(output_dir)
+  java_path = os.path.join(output_dir, RESOURCE_REWRITER_JAVA)
+  template = jinja2.Template(RESOURCE_REWRITER,
+                             trim_blocks=True,
+                             lstrip_blocks=True)
+  output = template.render(package=package, res_packages=res_packages)
+  with open(java_path, 'w') as f:
+    f.write(output)
+
+def CreateResourceRewriterSrcjar(package, res_packages, srcjar_path):
+  with build_utils.TempDir() as temp_dir:
+    output_dir = os.path.join(temp_dir, *package.split('.'))
+    CreateResourceRewriter(package, res_packages, output_dir)
+    build_utils.DoZip([os.path.join(output_dir, RESOURCE_REWRITER_JAVA)],
+                      srcjar_path,
+                      temp_dir)
+
+
+def main():
+  options = ParseArgs(build_utils.ExpandFileArgs(sys.argv[1:]))
+  package = options.package_name
+  if options.output_dir:
+    output_dir = os.path.join(options.output_dir, *package.split('.'))
+    CreateResourceRewriter(
+        package,
+        build_utils.ParseGypList(options.dep_packages),
+        output_dir)
+  else:
+    CreateResourceRewriterSrcjar(
+        package,
+        build_utils.ParseGypList(options.dep_packages),
+        options.srcjar)
+
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
+
diff --git a/build/android/gyp/generate_split_manifest.py b/build/android/gyp/generate_split_manifest.py
index 1c84fe7..9cb3bca 100755
--- a/build/android/gyp/generate_split_manifest.py
+++ b/build/android/gyp/generate_split_manifest.py
@@ -9,8 +9,8 @@
 the value required for a Split APK (package, versionCode, etc).
 """
 
-import lxml.etree
 import optparse
+import xml.etree.ElementTree
 
 from util import build_utils
 
@@ -19,6 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="%(package)s"
     split="%(split)s">
+  <uses-sdk android:minSdkVersion="21" />
   <application android:hasCode="%(has_code)s">
   </application>
 </manifest>
@@ -65,8 +66,8 @@
     The XML split manifest as a string
   """
 
-  doc = lxml.etree.fromstring(main_manifest)
-  package = doc.xpath('/manifest/@package')[0]
+  doc = xml.etree.ElementTree.fromstring(main_manifest)
+  package = doc.get('package')
 
   return MANIFEST_TEMPLATE % {
       'package': package,
@@ -89,7 +90,7 @@
   if options.depfile:
     build_utils.WriteDepfile(
         options.depfile,
-        [main_manifest] + build_utils.GetPythonDependencies())
+        [options.main_manifest] + build_utils.GetPythonDependencies())
 
 
 if __name__ == '__main__':
diff --git a/build/android/gyp/generate_v14_compatible_resources.py b/build/android/gyp/generate_v14_compatible_resources.py
index 7818170..fc7abba 100755
--- a/build/android/gyp/generate_v14_compatible_resources.py
+++ b/build/android/gyp/generate_v14_compatible_resources.py
@@ -19,6 +19,7 @@
 Please refer to http://crbug.com/235118 for the details.
 """
 
+import codecs
 import optparse
 import os
 import re
@@ -68,7 +69,7 @@
 def ParseAndReportErrors(filename):
   try:
     return minidom.parse(filename)
-  except Exception:
+  except Exception: # pylint: disable=broad-except
     import traceback
     traceback.print_exc()
     sys.stderr.write('Failed to parse XML file: %s\n' % filename)
@@ -96,7 +97,7 @@
 def WriteDomToFile(dom, filename):
   """Write the given dom to filename."""
   build_utils.MakeDirectory(os.path.dirname(filename))
-  with open(filename, 'w') as f:
+  with codecs.open(filename, 'w', 'utf-8') as f:
     dom.writexml(f, '', '  ', '\n', encoding='utf-8')
 
 
@@ -112,10 +113,14 @@
   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.')
+      # Allow style file in third_party to exist in non-v17 directories so long
+      # as they do not contain deprecated attributes.
+      if not 'third_party' in input_dir or (
+          GenerateV14StyleResourceDom(dom, input_filename)):
+        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):
@@ -231,36 +236,6 @@
     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.
 
@@ -275,10 +250,6 @@
                     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()
 
@@ -290,7 +261,7 @@
   build_utils.CheckOptions(options, parser, required=required_options)
   return options
 
-def GenerateV14Resources(res_dir, res_v14_dir, verify_only):
+def GenerateV14Resources(res_dir, res_v14_dir):
   for name in os.listdir(res_dir):
     if not os.path.isdir(os.path.join(res_dir, name)):
       continue
@@ -313,33 +284,27 @@
 
     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 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)
+    # 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()
@@ -349,7 +314,7 @@
   build_utils.DeleteDirectory(res_v14_dir)
   build_utils.MakeDirectory(res_v14_dir)
 
-  GenerateV14Resources(options.res_dir, res_v14_dir, options.verify_only)
+  GenerateV14Resources(options.res_dir, res_v14_dir)
 
   if options.stamp:
     build_utils.Touch(options.stamp)
diff --git a/build/android/gyp/jar.py b/build/android/gyp/jar.py
index 48abf5e..cbdc3ef 100755
--- a/build/android/gyp/jar.py
+++ b/build/android/gyp/jar.py
@@ -4,13 +4,11 @@
 # 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):
@@ -27,27 +25,18 @@
     jar_cmd.append(os.path.abspath(manifest_file))
   jar_cmd.extend(class_files_rel)
 
-  with build_utils.TempDir() as temp_dir:
-    empty_file = os.path.join(temp_dir, '.empty')
+  if not class_files_rel:
+    empty_file = os.path.join(classes_dir, '.empty')
     build_utils.Touch(empty_file)
     jar_cmd.append(os.path.relpath(empty_file, jar_cwd))
-    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)
+  build_utils.CheckOutput(jar_cmd, cwd=jar_cwd)
+  build_utils.Touch(jar_path, fail_if_missing=True)
 
 
-def JarDirectory(classes_dir, excluded_classes, jar_path, manifest_file=None):
+def JarDirectory(classes_dir, jar_path, manifest_file=None, predicate=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)
+  if predicate:
+    class_files = [f for f in class_files if predicate(f)]
 
   Jar(class_files, classes_dir, jar_path, manifest_file=manifest_file)
 
@@ -62,13 +51,12 @@
 
   options, _ = parser.parse_args()
 
+  predicate = None
   if options.excluded_classes:
     excluded_classes = build_utils.ParseGypList(options.excluded_classes)
-  else:
-    excluded_classes = []
-  JarDirectory(options.classes_dir,
-               excluded_classes,
-               options.jar_path)
+    predicate = lambda f: not build_utils.MatchesGlob(f, excluded_classes)
+
+  JarDirectory(options.classes_dir, options.jar_path, predicate=predicate)
 
   if options.stamp:
     build_utils.Touch(options.stamp)
diff --git a/build/android/gyp/jar_toc.py b/build/android/gyp/jar_toc.py
index 6d81008..774475b 100755
--- a/build/android/gyp/jar_toc.py
+++ b/build/android/gyp/jar_toc.py
@@ -44,6 +44,7 @@
       # -verbose is required to get constant values (which can be inlined in
       # dependents).
       '-verbose',
+      '-J-XX:NewSize=4m',
       '-classpath', classpath
       ] + classes
   return build_utils.CheckOutput(javap_cmd)
diff --git a/build/android/gyp/java_cpp_enum.py b/build/android/gyp/java_cpp_enum.py
index 1603959..9299bce 100755
--- a/build/android/gyp/java_cpp_enum.py
+++ b/build/android/gyp/java_cpp_enum.py
@@ -5,16 +5,21 @@
 # found in the LICENSE file.
 
 import collections
+from datetime import date
 import re
 import optparse
 import os
 from string import Template
 import sys
+import zipfile
 
 from util import build_utils
 
 # List of C++ types that are compatible with the Java code generated by this
 # script.
+#
+# This script can parse .idl files however, at present it ignores special
+# rules such as [cpp_enum_prefix_override="ax_attr"].
 ENUM_FIXED_TYPE_WHITELIST = ['char', 'unsigned char',
   'short', 'unsigned short',
   'int', 'int8_t', 'int16_t', 'int32_t', 'uint8_t', 'uint16_t']
@@ -134,8 +139,9 @@
   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*$')
+  enum_start_re = re.compile(r'^\s*(?:\[cpp.*\])?\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
@@ -228,8 +234,7 @@
   return os.sep.join(script_components[build_index:])
 
 
-def DoGenerate(output_dir, source_paths, print_output_only=False):
-  output_paths = []
+def DoGenerate(source_paths):
   for source_path in source_paths:
     enum_definitions = DoParseHeaderFile(source_path)
     if not enum_definitions:
@@ -240,12 +245,9 @@
     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
+      output_path = os.path.join(package_path, file_name)
+      output = GenerateOutput(source_path, enum_definition)
+      yield output_path, output
 
 
 def DoParseHeaderFile(path):
@@ -255,7 +257,7 @@
 
 def GenerateOutput(source_path, enum_definition):
   template = Template("""
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright ${YEAR} The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -287,14 +289,11 @@
       'PACKAGE': enum_definition.enum_package,
       'SCRIPT_NAME': GetScriptName(),
       'SOURCE_PATH': source_path,
+      'YEAR': str(date.today().year)
   }
   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)
@@ -305,32 +304,69 @@
                     'add %s and remove %s.' % (need_to_add, need_to_remove))
 
 def DoMain(argv):
-  usage = 'usage: %prog [options] output_dir input_file(s)...'
+  usage = 'usage: %prog [options] [output_dir] input_file(s)...'
   parser = optparse.OptionParser(usage=usage)
+  build_utils.AddDepfileOption(parser)
 
   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('--srcjar',
+                    help='When specified, a .srcjar at the given path is '
+                    'created instead of individual .java files.')
   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.srcjar:
+    if not args:
+      parser.error('Need to specify at least one input file')
+    input_paths = args
+  else:
+    if len(args) < 2:
+      parser.error(
+          'Need to specify output directory and at least one input file')
+    output_dir = args[0]
+    input_paths = args[1:]
 
-  if options.verbose:
-    print 'Output paths:'
-    print '\n'.join(output_paths)
+  if options.depfile:
+    python_deps = build_utils.GetPythonDependencies()
+    build_utils.WriteDepfile(options.depfile, input_paths + python_deps)
 
-  return ' '.join(output_paths)
+  if options.srcjar:
+    if options.print_output_only:
+      parser.error('--print_output_only does not work with --srcjar')
+    if options.assert_files_list:
+      parser.error('--assert_file does not work with --srcjar')
+
+    with zipfile.ZipFile(options.srcjar, 'w', zipfile.ZIP_STORED) as srcjar:
+      for output_path, data in DoGenerate(input_paths):
+        build_utils.AddToZipHermetic(srcjar, output_path, data=data)
+  else:
+    # TODO(agrieve): Delete this non-srcjar branch once GYP is gone.
+    output_paths = []
+    for output_path, data in DoGenerate(input_paths):
+      full_path = os.path.join(output_dir, output_path)
+      output_paths.append(full_path)
+      if not options.print_output_only:
+        build_utils.MakeDirectory(os.path.dirname(full_path))
+        with open(full_path, 'w') as out_file:
+          out_file.write(data)
+
+    if options.assert_files_list:
+      AssertFilesList(output_paths, options.assert_files_list)
+
+    if options.verbose:
+      print 'Output paths:'
+      print '\n'.join(output_paths)
+
+    # Used by GYP.
+    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
index 44f9766..902bbfa 100755
--- a/build/android/gyp/java_cpp_enum_tests.py
+++ b/build/android/gyp/java_cpp_enum_tests.py
@@ -9,6 +9,7 @@
 """
 
 import collections
+from datetime import date
 import optparse
 import os
 import sys
@@ -28,7 +29,7 @@
                                 entries=[('E1', 1), ('E2', '2 << 2')])
     output = GenerateOutput('path/to/file', definition)
     expected = """
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright %d The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -44,7 +45,7 @@
   public static final int E2 = 2 << 2;
 }
 """
-    self.assertEqual(expected % GetScriptName(), output)
+    self.assertEqual(expected % (date.today().year, GetScriptName()), output)
 
   def testParseSimpleEnum(self):
     test_data = """
@@ -417,7 +418,8 @@
       original_do_parse = java_cpp_enum.DoParseHeaderFile
       try:
         java_cpp_enum.DoParseHeaderFile = lambda _: []
-        java_cpp_enum.DoGenerate('dir', ['file'])
+        for _ in java_cpp_enum.DoGenerate(['file']):
+          pass
       finally:
         java_cpp_enum.DoParseHeaderFile = original_do_parse
 
diff --git a/build/android/gyp/java_google_api_keys.py b/build/android/gyp/java_google_api_keys.py
new file mode 100755
index 0000000..62c92cd
--- /dev/null
+++ b/build/android/gyp/java_google_api_keys.py
@@ -0,0 +1,129 @@
+#!/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.
+
+# Generates a Java file with API keys.
+
+import argparse
+import os
+import string
+import sys
+import zipfile
+
+from util import build_utils
+
+sys.path.append(
+    os.path.abspath(os.path.join(sys.path[0], '../../../google_apis')))
+import google_api_keys
+
+sys.path.append(os.path.abspath(os.path.join(
+    os.path.dirname(__file__), os.pardir)))
+from pylib import constants
+
+
+PACKAGE = 'org.chromium.chrome'
+CLASSNAME = 'GoogleAPIKeys'
+
+
+def GetScriptName():
+  return os.path.relpath(__file__, constants.DIR_SOURCE_ROOT)
+
+
+def GenerateOutput(constant_definitions):
+  template = string.Template("""
+// Copyright 2015 The Chromium Authors. All 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} {
+${CONSTANT_ENTRIES}
+}
+""")
+
+  constant_template = string.Template(
+      '  public static final String ${NAME} = "${VALUE}";')
+  constant_entries_list = []
+  for constant_name, constant_value in constant_definitions.iteritems():
+    values = {
+        'NAME': constant_name,
+        'VALUE': constant_value,
+    }
+    constant_entries_list.append(constant_template.substitute(values))
+  constant_entries_string = '\n'.join(constant_entries_list)
+
+  values = {
+      'CLASS_NAME': CLASSNAME,
+      'CONSTANT_ENTRIES': constant_entries_string,
+      'PACKAGE': PACKAGE,
+      'SCRIPT_NAME': GetScriptName(),
+      'SOURCE_PATH': 'google_api_keys/google_api_keys.h',
+  }
+  return template.substitute(values)
+
+
+def _DoWriteJavaOutput(output_path, constant_definition):
+  folder = os.path.dirname(output_path)
+  if folder and not os.path.exists(folder):
+    os.makedirs(folder)
+  with open(output_path, 'w') as out_file:
+    out_file.write(GenerateOutput(constant_definition))
+
+
+def _DoWriteJarOutput(output_path, constant_definition):
+  folder = os.path.dirname(output_path)
+  if folder and not os.path.exists(folder):
+    os.makedirs(folder)
+  with zipfile.ZipFile(output_path, 'w') as srcjar:
+    path = '%s/%s' % (PACKAGE.replace('.', '/'), CLASSNAME + '.java')
+    data = GenerateOutput(constant_definition)
+    build_utils.AddToZipHermetic(srcjar, path, data=data)
+
+
+def _DoMain(argv):
+  parser = argparse.ArgumentParser()
+  parser.add_argument("--out", help="Path for java output.")
+  parser.add_argument("--srcjar", help="Path for srcjar output.")
+  options = parser.parse_args(argv)
+  if not options.out and not options.srcjar:
+    parser.print_help()
+    sys.exit(-1)
+
+  values = {}
+  values['GOOGLE_API_KEY'] = google_api_keys.GetAPIKey()
+  values['GOOGLE_API_KEY_REMOTING'] = google_api_keys.GetAPIKeyRemoting()
+  values['GOOGLE_API_KEY_PHYSICAL_WEB_TEST'] = (google_api_keys.
+      GetAPIKeyPhysicalWebTest())
+  values['GOOGLE_CLIENT_ID_MAIN'] = google_api_keys.GetClientID('MAIN')
+  values['GOOGLE_CLIENT_SECRET_MAIN'] = google_api_keys.GetClientSecret('MAIN')
+  values['GOOGLE_CLIENT_ID_CLOUD_PRINT'] = google_api_keys.GetClientID(
+      'CLOUD_PRINT')
+  values['GOOGLE_CLIENT_SECRET_CLOUD_PRINT'] = google_api_keys.GetClientSecret(
+      'CLOUD_PRINT')
+  values['GOOGLE_CLIENT_ID_REMOTING'] = google_api_keys.GetClientID('REMOTING')
+  values['GOOGLE_CLIENT_SECRET_REMOTING'] = google_api_keys.GetClientSecret(
+      'REMOTING')
+  values['GOOGLE_CLIENT_ID_REMOTING_HOST'] = google_api_keys.GetClientID(
+      'REMOTING_HOST')
+  values['GOOGLE_CLIENT_SECRET_REMOTING_HOST'] = (google_api_keys.
+      GetClientSecret('REMOTING_HOST'))
+  values['GOOGLE_CLIENT_ID_REMOTING_IDENTITY_API'] = (google_api_keys.
+      GetClientID('REMOTING_IDENTITY_API'))
+
+  if options.out:
+    _DoWriteJavaOutput(options.out, values)
+  if options.srcjar:
+    _DoWriteJarOutput(options.srcjar, values)
+
+
+if __name__ == '__main__':
+  _DoMain(sys.argv[1:])
+
diff --git a/build/android/gyp/java_google_api_keys_tests.py b/build/android/gyp/java_google_api_keys_tests.py
new file mode 100755
index 0000000..eb24ea4
--- /dev/null
+++ b/build/android/gyp/java_google_api_keys_tests.py
@@ -0,0 +1,61 @@
+#!/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.
+
+"""Tests for java_google_api_keys.py.
+
+This test suite contains various tests for the C++ -> Java Google API Keys
+generator.
+"""
+
+import collections
+import argparse
+import os
+import sys
+import unittest
+
+import java_google_api_keys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "gyp"))
+from util import build_utils
+
+
+class TestJavaGoogleAPIKeys(unittest.TestCase):
+  def testOutput(self):
+    definition = {'E1': 'abc', 'E2': 'defgh'}
+    output = java_google_api_keys.GenerateOutput(definition)
+    expected = """
+// Copyright 2015 The Chromium Authors. All 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
+//     google_api_keys/google_api_keys.h
+
+package org.chromium.chrome;
+
+public class GoogleAPIKeys {
+  public static final String E1 = "abc";
+  public static final String E2 = "defgh";
+}
+"""
+    self.assertEqual(expected % java_google_api_keys.GetScriptName(), output)
+
+
+def main(argv):
+  parser = argparse.ArgumentParser()
+  parser.add_argument("--stamp", help="File to touch on success.")
+  options = parser.parse_args(argv)
+
+  suite = unittest.TestLoader().loadTestsFromTestCase(TestJavaGoogleAPIKeys)
+  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
index e36fd43..a818ff8 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -4,7 +4,6 @@
 # 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
@@ -54,61 +53,24 @@
   return '\n'.join(map(ApplyColor, output.split('\n')))
 
 
-def DoJavac(
-    classpath, classes_dir, chromium_code, java_files):
-  """Runs javac.
+ERRORPRONE_OPTIONS = [
+  # These crash on lots of targets.
+  '-Xep:ParameterPackage:OFF',
+  '-Xep:OverridesGuiceInjectableMethod:OFF',
+  '-Xep:OverridesJavaxInjectableMethod:OFF',
+]
 
-  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)
+def _FilterJavaFiles(paths, filters):
+  return [f for f in paths
+          if not filters or build_utils.MatchesGlob(f, filters)]
 
 
 _MAX_MANIFEST_LINE_LEN = 72
 
 
-def CreateManifest(manifest_path, classpath, main_class=None,
-                   manifest_entries=None):
+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
@@ -147,11 +109,175 @@
     f.write(output)
 
 
-def main(argv):
-  colorama.init()
+def _ExtractClassFiles(jar_path, dest_dir, java_files):
+  """Extracts all .class files not corresponding to |java_files|."""
+  # Two challenges exist here:
+  # 1. |java_files| have prefixes that are not represented in the the jar paths.
+  # 2. A single .java file results in multiple .class files when it contains
+  #    nested classes.
+  # Here's an example:
+  #   source path: ../../base/android/java/src/org/chromium/Foo.java
+  #   jar paths: org/chromium/Foo.class, org/chromium/Foo$Inner.class
+  # To extract only .class files not related to the given .java files, we strip
+  # off ".class" and "$*.class" and use a substring match against java_files.
+  def extract_predicate(path):
+    if not path.endswith('.class'):
+      return False
+    path_without_suffix = re.sub(r'(?:\$|\.)[^/]+class$', '', path)
+    partial_java_path = path_without_suffix + '.java'
+    return not any(p.endswith(partial_java_path) for p in java_files)
 
-  argv = build_utils.ExpandFileArgs(argv)
+  build_utils.ExtractAll(jar_path, path=dest_dir, predicate=extract_predicate)
+  for path in build_utils.FindInDirectory(dest_dir, '*.class'):
+    shutil.copystat(jar_path, path)
 
+
+def _ConvertToJMakeArgs(javac_cmd, pdb_path):
+  new_args = ['bin/jmake', '-pdb', pdb_path]
+  if javac_cmd[0] != 'javac':
+    new_args.extend(('-jcexec', new_args[0]))
+  if md5_check.PRINT_EXPLANATIONS:
+    new_args.append('-Xtiming')
+
+  do_not_prefix = ('-classpath', '-bootclasspath')
+  skip_next = False
+  for arg in javac_cmd[1:]:
+    if not skip_next and arg not in do_not_prefix:
+      arg = '-C' + arg
+    new_args.append(arg)
+    skip_next = arg in do_not_prefix
+
+  return new_args
+
+
+def _FixTempPathsInIncrementalMetadata(pdb_path, temp_dir):
+  # The .pdb records absolute paths. Fix up paths within /tmp (srcjars).
+  if os.path.exists(pdb_path):
+    # Although its a binary file, search/replace still seems to work fine.
+    with open(pdb_path) as fileobj:
+      pdb_data = fileobj.read()
+    with open(pdb_path, 'w') as fileobj:
+      fileobj.write(re.sub(r'/tmp/[^/]*', temp_dir, pdb_data))
+
+
+def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs,
+                runtime_classpath):
+  with build_utils.TempDir() as temp_dir:
+    srcjars = options.java_srcjars
+    # The .excluded.jar contains .class files excluded from the main jar.
+    # It is used for incremental compiles.
+    excluded_jar_path = options.jar_path.replace('.jar', '.excluded.jar')
+
+    classes_dir = os.path.join(temp_dir, 'classes')
+    os.makedirs(classes_dir)
+
+    changed_paths = None
+    # jmake can handle deleted files, but it's a rare case and it would
+    # complicate this script's logic.
+    if options.incremental and changes.AddedOrModifiedOnly():
+      changed_paths = set(changes.IterChangedPaths())
+      # Do a full compile if classpath has changed.
+      # jmake doesn't seem to do this on its own... Might be that ijars mess up
+      # its change-detection logic.
+      if any(p in changed_paths for p in classpath_inputs):
+        changed_paths = None
+
+    if options.incremental:
+      # jmake is a compiler wrapper that figures out the minimal set of .java
+      # files that need to be rebuilt given a set of .java files that have
+      # changed.
+      # jmake determines what files are stale based on timestamps between .java
+      # and .class files. Since we use .jars, .srcjars, and md5 checks,
+      # timestamp info isn't accurate for this purpose. Rather than use jmake's
+      # programatic interface (like we eventually should), we ensure that all
+      # .class files are newer than their .java files, and convey to jmake which
+      # sources are stale by having their .class files be missing entirely
+      # (by not extracting them).
+      pdb_path = options.jar_path + '.pdb'
+      javac_cmd = _ConvertToJMakeArgs(javac_cmd, pdb_path)
+      if srcjars:
+        _FixTempPathsInIncrementalMetadata(pdb_path, temp_dir)
+
+    if srcjars:
+      java_dir = os.path.join(temp_dir, 'java')
+      os.makedirs(java_dir)
+      for srcjar in options.java_srcjars:
+        if changed_paths:
+          changed_paths.update(os.path.join(java_dir, f)
+                               for f in changes.IterChangedSubpaths(srcjar))
+        build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java')
+      jar_srcs = build_utils.FindInDirectory(java_dir, '*.java')
+      jar_srcs = _FilterJavaFiles(jar_srcs, options.javac_includes)
+      java_files.extend(jar_srcs)
+      if changed_paths:
+        # Set the mtime of all sources to 0 since we use the absense of .class
+        # files to tell jmake which files are stale.
+        for path in jar_srcs:
+          os.utime(path, (0, 0))
+
+    if java_files:
+      if changed_paths:
+        changed_java_files = [p for p in java_files if p in changed_paths]
+        if os.path.exists(options.jar_path):
+          _ExtractClassFiles(options.jar_path, classes_dir, changed_java_files)
+        if os.path.exists(excluded_jar_path):
+          _ExtractClassFiles(excluded_jar_path, classes_dir, changed_java_files)
+        # Add the extracted files to the classpath. This is required because
+        # when compiling only a subset of files, classes that haven't changed
+        # need to be findable.
+        classpath_idx = javac_cmd.index('-classpath')
+        javac_cmd[classpath_idx + 1] += ':' + classes_dir
+
+      # Don't include the output directory in the initial set of args since it
+      # being in a temp dir makes it unstable (breaks md5 stamping).
+      cmd = javac_cmd + ['-d', classes_dir] + java_files
+
+      # JMake prints out some diagnostic logs that we want to ignore.
+      # This assumes that all compiler output goes through stderr.
+      stdout_filter = lambda s: ''
+      if md5_check.PRINT_EXPLANATIONS:
+        stdout_filter = None
+
+      attempt_build = lambda: build_utils.CheckOutput(
+          cmd,
+          print_stdout=options.chromium_code,
+          stdout_filter=stdout_filter,
+          stderr_filter=ColorJavacOutput)
+      try:
+        attempt_build()
+      except build_utils.CalledProcessError as e:
+        # Work-around for a bug in jmake (http://crbug.com/551449).
+        if 'project database corrupted' not in e.output:
+          raise
+        print ('Applying work-around for jmake project database corrupted '
+               '(http://crbug.com/551449).')
+        os.unlink(pdb_path)
+        attempt_build()
+
+    if options.main_class or options.manifest_entry:
+      entries = []
+      if options.manifest_entry:
+        entries = [e.split(':') for e in options.manifest_entry]
+      manifest_file = os.path.join(temp_dir, 'manifest')
+      _CreateManifest(manifest_file, runtime_classpath, options.main_class,
+                      entries)
+    else:
+      manifest_file = None
+
+    glob = options.jar_excluded_classes
+    inclusion_predicate = lambda f: not build_utils.MatchesGlob(f, glob)
+    exclusion_predicate = lambda f: not inclusion_predicate(f)
+
+    jar.JarDirectory(classes_dir,
+                     options.jar_path,
+                     manifest_file=manifest_file,
+                     predicate=inclusion_predicate)
+    jar.JarDirectory(classes_dir,
+                     excluded_jar_path,
+                     predicate=exclusion_predicate)
+
+
+def _ParseOptions(argv):
   parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
 
@@ -164,12 +290,28 @@
       default=[],
       help='List of srcjars to include in compilation.')
   parser.add_option(
+      '--bootclasspath',
+      action='append',
+      default=[],
+      help='Boot classpath for javac. If this is specified multiple times, '
+      'they will all be appended to construct the classpath.')
+  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(
+      '--use-ijars',
+      action='store_true',
+      help='Whether to use interface jars (.interface.jar) when compiling')
+  parser.add_option(
+      '--incremental',
+      action='store_true',
+      help='Whether to re-use .class files rather than recompiling them '
+           '(when possible).')
+  parser.add_option(
       '--javac-includes',
+      default='',
       help='A list of file patterns. If provided, only java files that match'
       'one of the patterns will be compiled.')
   parser.add_option(
@@ -184,8 +326,9 @@
       'warnings for chromium code.')
 
   parser.add_option(
-      '--classes-dir',
-      help='Directory for compiled .class files.')
+      '--use-errorprone-path',
+      help='Use the Errorprone compiler at this path.')
+
   parser.add_option('--jar-path', help='Jar output path.')
   parser.add_option(
       '--main-class',
@@ -198,85 +341,117 @@
   parser.add_option('--stamp', help='Path to touch on success.')
 
   options, args = parser.parse_args(argv)
+  build_utils.CheckOptions(options, parser, required=('jar_path',))
 
-  if options.main_class and not options.jar_path:
-    parser.error('--main-class requires --jar-path')
+  bootclasspath = []
+  for arg in options.bootclasspath:
+    bootclasspath += build_utils.ParseGypList(arg)
+  options.bootclasspath = bootclasspath
 
   classpath = []
   for arg in options.classpath:
     classpath += build_utils.ParseGypList(arg)
+  options.classpath = classpath
 
   java_srcjars = []
   for arg in options.java_srcjars:
     java_srcjars += build_utils.ParseGypList(arg)
+  options.java_srcjars = java_srcjars
 
-  java_files = args
   if options.src_gendirs:
-    src_gendirs = build_utils.ParseGypList(options.src_gendirs)
-    java_files += build_utils.FindInDirectories(src_gendirs, '*.java')
+    options.src_gendirs = build_utils.ParseGypList(options.src_gendirs)
 
-  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')
+  options.javac_includes = build_utils.ParseGypList(options.javac_includes)
+  options.jar_excluded_classes = (
+      build_utils.ParseGypList(options.jar_excluded_classes))
+  return options, args
 
-    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
 
-    if len(java_files) != 0:
-      DoJavac(
-          classpath,
-          classes_dir,
-          options.chromium_code,
-          java_files)
+def main(argv):
+  colorama.init()
 
-    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)
+  argv = build_utils.ExpandFileArgs(argv)
+  options, java_files = _ParseOptions(argv)
+
+  if options.src_gendirs:
+    java_files += build_utils.FindInDirectories(options.src_gendirs, '*.java')
+
+  java_files = _FilterJavaFiles(java_files, options.javac_includes)
+
+  runtime_classpath = options.classpath
+  compile_classpath = runtime_classpath
+  if options.use_ijars:
+    ijar_re = re.compile(r'\.jar$')
+    compile_classpath = (
+        [ijar_re.sub('.interface.jar', p) for p in runtime_classpath])
+
+  javac_cmd = ['javac']
+  if options.use_errorprone_path:
+    javac_cmd = [options.use_errorprone_path] + ERRORPRONE_OPTIONS
+
+  javac_cmd.extend((
+      '-g',
+      # Chromium only allows UTF8 source files.  Being explicit avoids
+      # javac pulling a default encoding from the user's environment.
+      '-encoding', 'UTF-8',
+      '-classpath', ':'.join(compile_classpath),
+      # Prevent compiler from compiling .java files not listed as inputs.
+      # See: http://blog.ltgt.net/most-build-tools-misuse-javac/
+      '-sourcepath', ''
+  ))
+
+  if options.bootclasspath:
+    javac_cmd.extend([
+        '-bootclasspath', ':'.join(options.bootclasspath),
+        '-source', '1.7',
+        '-target', '1.7',
+        ])
+
+  if options.chromium_code:
+    javac_cmd.extend(['-Xlint:unchecked', '-Xlint:deprecation'])
+  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_cmd.extend(['-XDignore.symbol.file'])
+
+  classpath_inputs = options.bootclasspath
+  # TODO(agrieve): Remove this .TOC heuristic once GYP is no more.
+  if options.use_ijars:
+    classpath_inputs.extend(compile_classpath)
+  else:
+    for path in compile_classpath:
+      if os.path.exists(path + '.TOC'):
+        classpath_inputs.append(path + '.TOC')
       else:
-        manifest_file = None
-      jar.JarDirectory(classes_dir,
-                       build_utils.ParseGypList(options.jar_excluded_classes),
-                       options.jar_path,
-                       manifest_file=manifest_file)
+        classpath_inputs.append(path)
 
-    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)
+  # Compute the list of paths that when changed, we need to rebuild.
+  input_paths = classpath_inputs + options.java_srcjars + java_files
 
-  if options.depfile:
-    build_utils.WriteDepfile(
-        options.depfile,
-        input_files + build_utils.GetPythonDependencies())
+  output_paths = [
+      options.jar_path,
+      options.jar_path.replace('.jar', '.excluded.jar'),
+  ]
+  if options.incremental:
+    output_paths.append(options.jar_path + '.pdb')
 
-  if options.stamp:
-    build_utils.Touch(options.stamp)
+  # An escape hatch to be able to check if incremental compiles are causing
+  # problems.
+  force = int(os.environ.get('DISABLE_INCREMENTAL_JAVAC', 0))
+
+  # List python deps in input_strings rather than input_paths since the contents
+  # of them does not change what gets written to the depsfile.
+  build_utils.CallAndWriteDepfileIfStale(
+      lambda changes: _OnStaleMd5(changes, options, javac_cmd, java_files,
+                                  classpath_inputs, runtime_classpath),
+      options,
+      input_paths=input_paths,
+      input_strings=javac_cmd,
+      output_paths=output_paths,
+      force=force,
+      pass_changes=True)
 
 
 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
index e7c9a34..a3633ae 100755
--- a/build/android/gyp/jinja_template.py
+++ b/build/android/gyp/jinja_template.py
@@ -11,10 +11,12 @@
 import os
 import sys
 
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from pylib import constants
 from util import build_utils
 
 # Import jinja2 from third_party/jinja2
-sys.path.append(os.path.join(os.path.dirname(__file__), '../../../third_party'))
+sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT, 'third_party'))
 import jinja2  # pylint: disable=F0401
 
 
@@ -76,8 +78,8 @@
                     '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)
+                    'the inputs. Defaults to DIR_SOURCE_ROOT.',
+                    default=constants.DIR_SOURCE_ROOT)
   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='')
diff --git a/build/android/gyp/lint.py b/build/android/gyp/lint.py
index 9402780..1e1779c 100755
--- a/build/android/gyp/lint.py
+++ b/build/android/gyp/lint.py
@@ -20,8 +20,7 @@
 
 
 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):
+             result_path, product_dir, sources, jar_path, resource_dir=None):
 
   def _RelativizePath(path):
     """Returns relative path to top-level src dir.
@@ -122,18 +121,18 @@
       if not os.path.exists(result_path):
         print 'Something is wrong:'
         print e
-        return 0
+        return 1
 
       # There are actual lint issues
       else:
         try:
           num_issues = _ParseAndShowResultFile()
-        except Exception:
+        except Exception: # pylint: disable=broad-except
           print 'Lint created unparseable xml file...'
           print 'File contents:'
           with open(result_path) as f:
             print f.read()
-          return 0
+          return 1
 
         _ProcessResultFile()
         msg = ('\nLint found %d new issues.\n'
@@ -148,7 +147,7 @@
                                              'lint', 'suppress.py')),
                 _RelativizePath(result_path)))
         print >> sys.stderr, msg
-        return 1 if can_fail_build else 0
+        return 1
 
   return 0
 
@@ -198,7 +197,7 @@
                   options.processed_config_path,
                   options.manifest_path, options.result_path,
                   options.product_dir, sources, options.jar_path,
-                  options.resource_dir, options.can_fail_build)
+                  options.resource_dir)
 
   if options.depfile:
     build_utils.WriteDepfile(
@@ -208,7 +207,7 @@
   if options.stamp and not rc:
     build_utils.Touch(options.stamp)
 
-  return rc
+  return rc if options.can_fail_build else 0
 
 
 if __name__ == '__main__':
diff --git a/build/android/gyp/locale_pak_resources.py b/build/android/gyp/locale_pak_resources.py
new file mode 100755
index 0000000..84c4a37
--- /dev/null
+++ b/build/android/gyp/locale_pak_resources.py
@@ -0,0 +1,126 @@
+#!/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.
+"""Creates a resources.zip for locale .pak files.
+
+Places the locale.pak files into appropriate resource configs
+(e.g. en-GB.pak -> res/raw-en/en_gb.lpak). Also generates a locale_paks
+TypedArray so that resource files can be enumerated at runtime.
+"""
+
+import collections
+import optparse
+import os
+import sys
+import zipfile
+
+from util import build_utils
+
+
+# This should stay in sync with:
+# base/android/java/src/org/chromium/base/LocaleUtils.java
+_CHROME_TO_ANDROID_LOCALE_MAP = {
+    'he': 'iw',
+    'id': 'in',
+    'fil': 'tl',
+}
+
+
+def ToResourceFileName(name):
+  """Returns the resource-compatible file name for the given file."""
+  # Resources file names must consist of [a-z0-9_.].
+  # Changes extension to .lpak so that compression can be toggled separately for
+  # locale pak files vs other pak files.
+  return name.replace('-', '_').replace('.pak', '.lpak').lower()
+
+
+def CreateLocalePaksXml(names):
+  """Creates the contents for the locale-paks.xml files."""
+  VALUES_FILE_TEMPLATE = '''<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <array name="locale_paks">%s
+  </array>
+</resources>
+'''
+  VALUES_ITEM_TEMPLATE = '''
+    <item>@raw/%s</item>'''
+
+  res_names = (os.path.splitext(name)[0] for name in names)
+  items = ''.join((VALUES_ITEM_TEMPLATE % name for name in res_names))
+  return VALUES_FILE_TEMPLATE % items
+
+
+def ComputeMappings(sources):
+  """Computes the mappings of sources -> resources.
+
+  Returns a tuple of:
+    - mappings: List of (src, dest) paths
+    - lang_to_locale_map: Map of language -> list of resource names
+      e.g. "en" -> ["en_gb.lpak"]
+  """
+  lang_to_locale_map = collections.defaultdict(list)
+  mappings = []
+  for src_path in sources:
+    basename = os.path.basename(src_path)
+    name = os.path.splitext(basename)[0]
+    res_name = ToResourceFileName(basename)
+    if name == 'en-US':
+      dest_dir = 'raw'
+    else:
+      # Chrome's uses different region mapping logic from Android, so include
+      # all regions for each language.
+      android_locale = _CHROME_TO_ANDROID_LOCALE_MAP.get(name, name)
+      lang = android_locale[0:2]
+      dest_dir = 'raw-' + lang
+      lang_to_locale_map[lang].append(res_name)
+    mappings.append((src_path, os.path.join(dest_dir, res_name)))
+  return mappings, lang_to_locale_map
+
+
+def main():
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option('--locale-paks', help='List of files for res/raw-LOCALE')
+  parser.add_option('--resources-zip', help='Path to output resources.zip')
+  parser.add_option('--print-languages',
+      action='store_true',
+      help='Print out the list of languages that cover the given locale paks '
+           '(using Android\'s language codes)')
+
+  options, _ = parser.parse_args()
+  build_utils.CheckOptions(options, parser,
+                           required=['locale_paks'])
+
+  sources = build_utils.ParseGypList(options.locale_paks)
+
+  if options.depfile:
+    deps = sources + build_utils.GetPythonDependencies()
+    build_utils.WriteDepfile(options.depfile, deps)
+
+  mappings, lang_to_locale_map = ComputeMappings(sources)
+  if options.print_languages:
+    print '\n'.join(sorted(lang_to_locale_map))
+
+  if options.resources_zip:
+    with zipfile.ZipFile(options.resources_zip, 'w', zipfile.ZIP_STORED) as out:
+      for mapping in mappings:
+        out.write(mapping[0], mapping[1])
+
+      # Create TypedArray resources so ResourceExtractor can enumerate files.
+      def WriteValuesFile(lang, names):
+        dest_dir = 'values'
+        if lang:
+          dest_dir += '-' + lang
+        # Always extract en-US.lpak since it's the fallback.
+        xml = CreateLocalePaksXml(names + ['en_us.lpak'])
+        out.writestr(os.path.join(dest_dir, 'locale-paks.xml'), xml)
+
+      for lang, names in lang_to_locale_map.iteritems():
+        WriteValuesFile(lang, names)
+      WriteValuesFile(None, [])
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/main_dex_list.py b/build/android/gyp/main_dex_list.py
new file mode 100755
index 0000000..7388f4a
--- /dev/null
+++ b/build/android/gyp/main_dex_list.py
@@ -0,0 +1,138 @@
+#!/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 argparse
+import json
+import os
+import sys
+import tempfile
+
+from util import build_utils
+
+sys.path.append(os.path.abspath(os.path.join(
+    os.path.dirname(__file__), os.pardir)))
+from pylib import constants
+
+
+def main(args):
+  parser = argparse.ArgumentParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_argument('--android-sdk-tools', required=True,
+                      help='Android sdk build tools directory.')
+  parser.add_argument('--main-dex-rules-path', action='append', default=[],
+                      dest='main_dex_rules_paths',
+                      help='A file containing a list of proguard rules to use '
+                           'in determining the class to include in the '
+                           'main dex.')
+  parser.add_argument('--main-dex-list-path', required=True,
+                      help='The main dex list file to generate.')
+  parser.add_argument('--enabled-configurations',
+                      help='The build configurations for which a main dex list'
+                           ' should be generated.')
+  parser.add_argument('--configuration-name',
+                      help='The current build configuration.')
+  parser.add_argument('--multidex-configuration-path',
+                      help='A JSON file containing multidex build '
+                           'configuration.')
+  parser.add_argument('--inputs',
+                      help='JARs for which a main dex list should be '
+                           'generated.')
+  parser.add_argument('paths', nargs='*', default=[],
+                      help='JARs for which a main dex list should be '
+                           'generated.')
+
+  args = parser.parse_args(build_utils.ExpandFileArgs(args))
+
+  if args.multidex_configuration_path:
+    with open(args.multidex_configuration_path) as multidex_config_file:
+      multidex_config = json.loads(multidex_config_file.read())
+
+    if not multidex_config.get('enabled', False):
+      return 0
+
+  if args.inputs:
+    args.paths.extend(build_utils.ParseGypList(args.inputs))
+
+  shrinked_android_jar = os.path.abspath(
+      os.path.join(args.android_sdk_tools, 'lib', 'shrinkedAndroid.jar'))
+  dx_jar = os.path.abspath(
+      os.path.join(args.android_sdk_tools, 'lib', 'dx.jar'))
+  rules_file = os.path.abspath(
+      os.path.join(args.android_sdk_tools, 'mainDexClasses.rules'))
+
+  proguard_cmd = [
+    constants.PROGUARD_SCRIPT_PATH,
+    '-forceprocessing',
+    '-dontwarn', '-dontoptimize', '-dontobfuscate', '-dontpreverify',
+    '-libraryjars', shrinked_android_jar,
+    '-include', rules_file,
+  ]
+  for m in args.main_dex_rules_paths:
+    proguard_cmd.extend(['-include', m])
+
+  main_dex_list_cmd = [
+    'java', '-cp', dx_jar,
+    'com.android.multidex.MainDexListBuilder',
+  ]
+
+  input_paths = list(args.paths)
+  input_paths += [
+    shrinked_android_jar,
+    dx_jar,
+    rules_file,
+  ]
+  input_paths += args.main_dex_rules_paths
+
+  input_strings = [
+    proguard_cmd,
+    main_dex_list_cmd,
+  ]
+
+  output_paths = [
+    args.main_dex_list_path,
+  ]
+
+  build_utils.CallAndWriteDepfileIfStale(
+      lambda: _OnStaleMd5(proguard_cmd, main_dex_list_cmd, args.paths,
+                          args.main_dex_list_path),
+      args,
+      input_paths=input_paths,
+      input_strings=input_strings,
+      output_paths=output_paths)
+
+  return 0
+
+
+def _OnStaleMd5(proguard_cmd, main_dex_list_cmd, paths, main_dex_list_path):
+  paths_arg = ':'.join(paths)
+  main_dex_list = ''
+  try:
+    with tempfile.NamedTemporaryFile(suffix='.jar') as temp_jar:
+      proguard_cmd += [
+        '-injars', paths_arg,
+        '-outjars', temp_jar.name
+      ]
+      build_utils.CheckOutput(proguard_cmd, print_stderr=False)
+
+      main_dex_list_cmd += [
+        temp_jar.name, paths_arg
+      ]
+      main_dex_list = build_utils.CheckOutput(main_dex_list_cmd)
+  except build_utils.CalledProcessError as e:
+    if 'output jar is empty' in e.output:
+      pass
+    elif "input doesn't contain any classes" in e.output:
+      pass
+    else:
+      raise
+
+  with open(main_dex_list_path, 'w') as main_dex_list_file:
+    main_dex_list_file.write(main_dex_list)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
+
diff --git a/build/android/gyp/pack_arm_relocations.py b/build/android/gyp/pack_arm_relocations.py
deleted file mode 100755
index 517a22e..0000000
--- a/build/android/gyp/pack_arm_relocations.py
+++ /dev/null
@@ -1,137 +0,0 @@
-#!/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/pack_relocations.py b/build/android/gyp/pack_relocations.py
new file mode 100755
index 0000000..1a4824a
--- /dev/null
+++ b/build/android/gyp/pack_relocations.py
@@ -0,0 +1,114 @@
+#!/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 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.
+
+If --enable-packing is zero, the script copies files verbatim, with no
+attempt to pack 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 shutil
+import sys
+import tempfile
+
+from util import build_utils
+
+def PackLibraryRelocations(android_pack_relocations, library_path, output_path):
+  shutil.copy(library_path, output_path)
+  pack_command = [android_pack_relocations, output_path]
+  build_utils.CheckOutput(pack_command)
+
+
+def CopyLibraryUnchanged(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('--exclude-packing-list',
+      default='',
+      help='Names of any libraries explicitly not packed')
+  parser.add_option('--android-pack-relocations',
+      help='Path to the relocations packer 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')
+  parser.add_option('--filelistjson',
+                    help='Output path of filelist.json to write')
+
+  options, _ = parser.parse_args(args)
+  enable_packing = (options.enable_packing == '1' and
+                    options.configuration_name == 'Release')
+  exclude_packing_set = set(build_utils.ParseGypList(
+      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)
+
+  output_paths = []
+  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))
+    output_paths.append(output_path)
+
+    if enable_packing and library not in exclude_packing_set:
+      PackLibraryRelocations(options.android_pack_relocations,
+                             library_path,
+                             output_path)
+    else:
+      CopyLibraryUnchanged(library_path, output_path)
+
+  if options.filelistjson:
+    build_utils.WriteJson({ 'files': output_paths }, options.filelistjson)
+
+  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
index 2251de0..a1f3840 100755
--- a/build/android/gyp/package_resources.py
+++ b/build/android/gyp/package_resources.py
@@ -15,11 +15,64 @@
 
 import optparse
 import os
+import re
 import shutil
+import sys
+import zipfile
 
 from util import build_utils
 
-def ParseArgs():
+
+# List is generated from the chrome_apk.apk_intermediates.ap_ via:
+#     unzip -l $FILE_AP_ | cut -c31- | grep res/draw | cut -d'/' -f 2 | sort \
+#     | uniq | grep -- -tvdpi- | cut -c10-
+# and then manually sorted.
+# Note that we can't just do a cross-product of dimentions because the filenames
+# become too big and aapt fails to create the files.
+# This leaves all default drawables (mdpi) in the main apk. Android gets upset
+# though if any drawables are missing from the default drawables/ directory.
+DENSITY_SPLITS = {
+    'hdpi': (
+        'hdpi-v4', # Order matters for output file names.
+        'ldrtl-hdpi-v4',
+        'sw600dp-hdpi-v13',
+        'ldrtl-hdpi-v17',
+        'ldrtl-sw600dp-hdpi-v17',
+        'hdpi-v21',
+    ),
+    'xhdpi': (
+        'xhdpi-v4',
+        'ldrtl-xhdpi-v4',
+        'sw600dp-xhdpi-v13',
+        'ldrtl-xhdpi-v17',
+        'ldrtl-sw600dp-xhdpi-v17',
+        'xhdpi-v21',
+    ),
+    'xxhdpi': (
+        'xxhdpi-v4',
+        'ldrtl-xxhdpi-v4',
+        'sw600dp-xxhdpi-v13',
+        'ldrtl-xxhdpi-v17',
+        'ldrtl-sw600dp-xxhdpi-v17',
+        'xxhdpi-v21',
+    ),
+    'xxxhdpi': (
+        'xxxhdpi-v4',
+        'ldrtl-xxxhdpi-v4',
+        'sw600dp-xxxhdpi-v13',
+        'ldrtl-xxxhdpi-v17',
+        'ldrtl-sw600dp-xxxhdpi-v17',
+        'xxxhdpi-v21',
+    ),
+    'tvdpi': (
+        'tvdpi-v4',
+        'sw600dp-tvdpi-v13',
+        'ldrtl-sw600dp-tvdpi-v17',
+    ),
+}
+
+
+def _ParseArgs(args):
   """Parses command line options.
 
   Returns:
@@ -28,8 +81,8 @@
   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('--aapt-path',
+                    help='path to the Android aapt tool')
 
   parser.add_option('--configuration-name',
                     help='Gyp\'s configuration name (Debug or Release).')
@@ -42,28 +95,42 @@
       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(
+      '--app-as-shared-lib',
+      action='store_true',
+      help='Make a resource package that can be loaded as shared library')
   parser.add_option('--resource-zips',
+                    default='[]',
                     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(
+      '--create-density-splits',
+      action='store_true',
+      help='Enables density splits')
+  parser.add_option('--language-splits',
+                    default='[]',
+                    help='GYP list of languages to create splits for')
 
   parser.add_option('--apk-path',
                     help='Path to output (partial) apk.')
 
-  (options, args) = parser.parse_args()
+  options, positional_args = parser.parse_args(args)
 
-  if args:
+  if positional_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',
+  required_options = ('android_sdk', 'aapt_path', 'configuration_name',
                       'android_manifest', 'version_code', 'version_name',
-                      'resource_zips', 'asset_dir', 'apk_path')
+                      'apk_path')
 
   build_utils.CheckOptions(options, parser, required=required_options)
 
+  options.resource_zips = build_utils.ParseGypList(options.resource_zips)
+  options.language_splits = build_utils.ParseGypList(options.language_splits)
   return options
 
 
@@ -114,54 +181,143 @@
   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')
+def _GenerateDensitySplitPaths(apk_path):
+  for density, config in DENSITY_SPLITS.iteritems():
+    src_path = '%s_%s' % (apk_path, '_'.join(config))
+    dst_path = '%s_%s' % (apk_path, density)
+    yield src_path, dst_path
 
+
+def _GenerateLanguageSplitOutputPaths(apk_path, languages):
+  for lang in languages:
+    yield '%s_%s' % (apk_path, lang)
+
+
+def RenameDensitySplits(apk_path):
+  """Renames all density splits to have shorter / predictable names."""
+  for src_path, dst_path in _GenerateDensitySplitPaths(apk_path):
+    shutil.move(src_path, dst_path)
+
+
+def CheckForMissedConfigs(apk_path, check_density, languages):
+  """Raises an exception if apk_path contains any unexpected configs."""
+  triggers = []
+  if check_density:
+    triggers.extend(re.compile('-%s' % density) for density in DENSITY_SPLITS)
+  if languages:
+    triggers.extend(re.compile(r'-%s\b' % lang) for lang in languages)
+  with zipfile.ZipFile(apk_path) as main_apk_zip:
+    for name in main_apk_zip.namelist():
+      for trigger in triggers:
+        if trigger.search(name) and not 'mipmap-' in name:
+          raise Exception(('Found config in main apk that should have been ' +
+                           'put into a split: %s\nYou need to update ' +
+                           'package_resources.py to include this new ' +
+                           'config (trigger=%s)') % (name, trigger.pattern))
+
+
+def _ConstructMostAaptArgs(options):
+  package_command = [
+      options.aapt_path,
+      'package',
+      '--version-code', options.version_code,
+      '--version-name', options.version_name,
+      '-M', options.android_manifest,
+      '--no-crunch',
+      '-f',
+      '--auto-add-overlay',
+      '-I', os.path.join(options.android_sdk, '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 options.app_as_shared_lib:
+    package_command.append('--app-as-shared-lib')
+
+  if options.asset_dir and os.path.exists(options.asset_dir):
+    package_command += ['-A', options.asset_dir]
+
+  if options.create_density_splits:
+    for config in DENSITY_SPLITS.itervalues():
+      package_command.extend(('--split', ','.join(config)))
+
+  if options.language_splits:
+    for lang in options.language_splits:
+      package_command.extend(('--split', lang))
+
+  if 'Debug' in options.configuration_name:
+    package_command += ['--debug-mode']
+
+  return package_command
+
+
+def _OnStaleMd5(package_command, options):
   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']
+    if options.resource_zips:
+      dep_zips = 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)
 
     build_utils.CheckOutput(
         package_command, print_stdout=False, print_stderr=False)
 
-    if options.depfile:
-      build_utils.WriteDepfile(
-          options.depfile,
-          build_utils.GetPythonDependencies())
+    if options.create_density_splits or options.language_splits:
+      CheckForMissedConfigs(options.apk_path, options.create_density_splits,
+                            options.language_splits)
+
+    if options.create_density_splits:
+      RenameDensitySplits(options.apk_path)
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  options = _ParseArgs(args)
+
+  package_command = _ConstructMostAaptArgs(options)
+
+  output_paths = [ options.apk_path ]
+
+  if options.create_density_splits:
+    for _, dst_path in _GenerateDensitySplitPaths(options.apk_path):
+      output_paths.append(dst_path)
+  output_paths.extend(
+      _GenerateLanguageSplitOutputPaths(options.apk_path,
+                                        options.language_splits))
+
+  input_paths = [ options.android_manifest ] + options.resource_zips
+
+  input_strings = []
+  input_strings.extend(package_command)
+
+  # The md5_check.py doesn't count file path in md5 intentionally,
+  # in order to repackage resources when assets' name changed, we need
+  # to put assets into input_strings, as we know the assets path isn't
+  # changed among each build if there is no asset change.
+  if options.asset_dir and os.path.exists(options.asset_dir):
+    asset_paths = []
+    for root, _, filenames in os.walk(options.asset_dir):
+      asset_paths.extend(os.path.join(root, f) for f in filenames)
+    input_paths.extend(asset_paths)
+    input_strings.extend(sorted(asset_paths))
+
+  build_utils.CallAndWriteDepfileIfStale(
+      lambda: _OnStaleMd5(package_command, options),
+      options,
+      input_paths=input_paths,
+      input_strings=input_strings,
+      output_paths=output_paths)
 
 
 if __name__ == '__main__':
-  main()
+  main(sys.argv[1:])
diff --git a/build/android/gyp/process_resources.py b/build/android/gyp/process_resources.py
index 4914189..441a798 100755
--- a/build/android/gyp/process_resources.py
+++ b/build/android/gyp/process_resources.py
@@ -11,23 +11,29 @@
 """
 
 import codecs
+import collections
 import optparse
 import os
 import re
 import shutil
 import sys
-import zipfile
 
 import generate_v14_compatible_resources
 
 from util import build_utils
 
 # Import jinja2 from third_party/jinja2
-sys.path.append(os.path.join(os.path.dirname(__file__), '../../../third_party'))
+sys.path.insert(1,
+    os.path.join(os.path.dirname(__file__), '../../../third_party'))
 from jinja2 import Template # pylint: disable=F0401
 
 
-def ParseArgs(args):
+# Represents a line from a R.txt file.
+TextSymbolsEntry = collections.namedtuple('RTextEntry',
+    ('java_type', 'resource_type', 'name', 'value'))
+
+
+def _ParseArgs(args):
   """Parses command line options.
 
   Returns:
@@ -37,8 +43,8 @@
   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('--aapt-path',
+                    help='path to the Android aapt tool')
   parser.add_option('--non-constant-id', action='store_true')
 
   parser.add_option('--android-manifest', help='AndroidManifest.xml path')
@@ -48,6 +54,10 @@
       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(
+      '--app-as-shared-lib',
+      action='store_true',
+      help='Make a resource package that can be loaded as shared library.')
 
   parser.add_option('--resource-dirs',
                     help='Directories containing resources of this target.')
@@ -68,12 +78,6 @@
                     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(
       '--v14-skip',
       action="store_true",
       help='Do not generate nor verify v14 resources')
@@ -99,15 +103,15 @@
 
   parser.add_option('--stamp', help='File to touch on success')
 
-  (options, args) = parser.parse_args(args)
+  options, positional_args = parser.parse_args(args)
 
-  if args:
+  if positional_args:
     parser.error('No positional arguments should be given.')
 
   # Check that required options have been provided.
   required_options = (
       'android_sdk',
-      'android_sdk_tools',
+      'aapt_path',
       'android_manifest',
       'dependencies_res_zips',
       'resource_dirs',
@@ -118,6 +122,23 @@
   if (options.R_dir is None) == (options.srcjar_out is None):
     raise Exception('Exactly one of --R-dir or --srcjar-out must be specified.')
 
+  options.resource_dirs = build_utils.ParseGypList(options.resource_dirs)
+  options.dependencies_res_zips = (
+      build_utils.ParseGypList(options.dependencies_res_zips))
+
+  # Don't use [] as default value since some script explicitly pass "".
+  if options.extra_res_packages:
+    options.extra_res_packages = (
+        build_utils.ParseGypList(options.extra_res_packages))
+  else:
+    options.extra_res_packages = []
+
+  if options.extra_r_text_files:
+    options.extra_r_text_files = (
+        build_utils.ParseGypList(options.extra_r_text_files))
+  else:
+    options.extra_r_text_files = []
+
   return options
 
 
@@ -141,42 +162,61 @@
     if len(extra_packages) != len(extra_r_text_files):
       raise Exception('Need one R.txt file per extra package')
 
-    all_resources = {}
     r_txt_file = os.path.join(r_dir, 'R.txt')
     if not os.path.exists(r_txt_file):
       return
-    with open(r_txt_file) as f:
-      for line in f:
-        m = re.match(r'(int(?:\[\])?) (\w+) (\w+) (.+)$', line)
-        if not m:
-          raise Exception('Unexpected line in R.txt: %s' % line)
-        java_type, resource_type, name, value = m.groups()
-        all_resources[(resource_type, name)] = (java_type, value)
 
+    # Map of (resource_type, name) -> Entry.
+    # Contains the correct values for resources.
+    all_resources = {}
+    for entry in _ParseTextSymbolsFile(r_txt_file):
+      all_resources[(entry.resource_type, entry.name)] = entry
+
+    # Map of package_name->resource_type->entry
+    resources_by_package = (
+        collections.defaultdict(lambda: collections.defaultdict(list)))
+    # Build the R.java files using each package's R.txt file, but replacing
+    # each entry's placeholder value with correct values from all_resources.
     for package, r_text_file in zip(extra_packages, extra_r_text_files):
-      if os.path.exists(r_text_file):
-        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')
-        CreateExtraRJavaFile(
-            package, package_r_java_path, r_text_file, all_resources,
-            shared_resources)
+      if not os.path.exists(r_text_file):
+        continue
+      if package in resources_by_package:
+        raise Exception(('Package name "%s" appeared twice. All '
+                         'android_resources() targets must use unique package '
+                         'names, or no package name at all.') % package)
+      resources_by_type = resources_by_package[package]
+      # The sub-R.txt files have the wrong values at this point. Read them to
+      # figure out which entries belong to them, but use the values from the
+      # main R.txt file.
+      for entry in _ParseTextSymbolsFile(r_text_file):
+        entry = all_resources[(entry.resource_type, entry.name)]
+        resources_by_type[entry.resource_type].append(entry)
+
+    for package, resources_by_type in resources_by_package.iteritems():
+      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')
+      java_file_contents = _CreateExtraRJavaFile(
+          package, resources_by_type, shared_resources)
+      with open(package_r_java_path, 'w') as f:
+        f.write(java_file_contents)
 
 
-def CreateExtraRJavaFile(
-      package, r_java_path, r_text_file, all_resources, shared_resources):
-  resources = {}
-  with open(r_text_file) as f:
+def _ParseTextSymbolsFile(path):
+  """Given an R.txt file, returns a list of TextSymbolsEntry."""
+  ret = []
+  with open(path) as f:
     for line in f:
-      m = re.match(r'int(?:\[\])? (\w+) (\w+) ', line)
+      m = re.match(r'(int(?:\[\])?) (\w+) (\w+) (.+)$', line)
       if not m:
         raise Exception('Unexpected line in R.txt: %s' % line)
-      resource_type, name = m.groups()
-      java_type, value = all_resources[(resource_type, name)]
-      if resource_type not in resources:
-        resources[resource_type] = []
-      resources[resource_type].append((name, java_type, value))
+      java_type, resource_type, name, value = m.groups()
+      ret.append(TextSymbolsEntry(java_type, resource_type, name, value))
+  return ret
 
+
+def _CreateExtraRJavaFile(package, resources_by_type, shared_resources):
+  """Generates the contents of a R.java file."""
   template = Template("""/* AUTO-GENERATED FILE.  DO NOT MODIFY. */
 
 package {{ package }};
@@ -184,11 +224,11 @@
 public final class R {
     {% for resource_type in resources %}
     public static final class {{ resource_type }} {
-        {% for name, java_type, value in resources[resource_type] %}
+        {% for e in resources[resource_type] %}
         {% if shared_resources %}
-        public static {{ java_type }} {{ name }} = {{ value }};
+        public static {{ e.java_type }} {{ e.name }} = {{ e.value }};
         {% else %}
-        public static final {{ java_type }} {{ name }} = {{ value }};
+        public static final {{ e.java_type }} {{ e.name }} = {{ e.value }};
         {% endif %}
         {% endfor %}
     }
@@ -196,16 +236,16 @@
     {% if shared_resources %}
     public static void onResourcesLoaded(int packageId) {
         {% for resource_type in resources %}
-        {% for name, java_type, value in resources[resource_type] %}
-        {% if java_type == 'int[]' %}
-        for(int i = 0; i < {{ resource_type }}.{{ name }}.length; ++i) {
-            {{ resource_type }}.{{ name }}[i] =
-                    ({{ resource_type }}.{{ name }}[i] & 0x00ffffff)
+        {% for e in resources[resource_type] %}
+        {% if e.java_type == 'int[]' %}
+        for(int i = 0; i < {{ e.resource_type }}.{{ e.name }}.length; ++i) {
+            {{ e.resource_type }}.{{ e.name }}[i] =
+                    ({{ e.resource_type }}.{{ e.name }}[i] & 0x00ffffff)
                     | (packageId << 24);
         }
         {% else %}
-        {{ resource_type }}.{{ name }} =
-                ({{ resource_type }}.{{ name }} & 0x00ffffff)
+        {{ e.resource_type }}.{{ e.name }} =
+                ({{ e.resource_type }}.{{ e.name }} & 0x00ffffff)
                 | (packageId << 24);
         {% endif %}
         {% endfor %}
@@ -215,10 +255,8 @@
 }
 """, trim_blocks=True, lstrip_blocks=True)
 
-  output = template.render(package=package, resources=resources,
-                           shared_resources=shared_resources)
-  with open(r_java_path, 'w') as f:
-    f.write(output)
+  return template.render(package=package, resources=resources_by_type,
+                         shared_resources=shared_resources)
 
 
 def CrunchDirectory(aapt, input_dir, output_dir):
@@ -281,12 +319,13 @@
   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)
+        archive_path = f
+        parent_dir = os.path.relpath(root, d)
+        if parent_dir != '.':
+          archive_path = os.path.join(parent_dir, 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)
+  build_utils.DoZip(files_to_zip.iteritems(), zip_path)
 
 
 def CombineZips(zip_files, output_path):
@@ -295,23 +334,15 @@
   # 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 path_transform(name, src_zip):
+    return '%d/%s' % (zip_files.index(src_zip), name)
+
+  build_utils.MergeZips(output_path, zip_files, path_transform=path_transform)
 
 
-def main():
-  args = build_utils.ExpandFileArgs(sys.argv[1:])
-
-  options = ParseArgs(args)
+def _OnStaleMd5(options):
   android_jar = os.path.join(options.android_sdk, 'android.jar')
-  aapt = os.path.join(options.android_sdk_tools, 'aapt')
-
-  input_files = []
-
+  aapt = options.aapt_path
   with build_utils.TempDir() as temp_dir:
     deps_dir = os.path.join(temp_dir, 'deps')
     build_utils.MakeDirectory(deps_dir)
@@ -321,17 +352,15 @@
     gen_dir = os.path.join(temp_dir, 'gen')
     build_utils.MakeDirectory(gen_dir)
 
-    input_resource_dirs = build_utils.ParseGypList(options.resource_dirs)
+    input_resource_dirs = options.resource_dirs
 
     if not options.v14_skip:
       for resource_dir in input_resource_dirs:
         generate_v14_compatible_resources.GenerateV14Resources(
             resource_dir,
-            v14_dir,
-            options.v14_verify_only)
+            v14_dir)
 
-    dep_zips = build_utils.ParseGypList(options.dependencies_res_zips)
-    input_files += dep_zips
+    dep_zips = options.dependencies_res_zips
     dep_subdirs = []
     for z in dep_zips:
       subdir = os.path.join(deps_dir, os.path.basename(z))
@@ -369,14 +398,16 @@
       package_command += ['-G', options.proguard_file]
     if options.shared_resources:
       package_command.append('--shared-lib')
+    if options.app_as_shared_lib:
+      package_command.append('--app-as-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),
-          build_utils.ParseGypList(options.extra_r_text_files),
-          options.shared_resources,
+          options.extra_res_packages,
+          options.extra_r_text_files,
+          options.shared_resources or options.app_as_shared_lib,
           options.include_all_resources)
 
     # This is the list of directories with resources to put in the final .zip
@@ -414,13 +445,50 @@
       else:
         open(options.r_text_out, 'w').close()
 
-  if options.depfile:
-    input_files += build_utils.GetPythonDependencies()
-    build_utils.WriteDepfile(options.depfile, input_files)
 
-  if options.stamp:
-    build_utils.Touch(options.stamp)
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  options = _ParseArgs(args)
+
+  possible_output_paths = [
+    options.resource_zip_out,
+    options.all_resources_zip_out,
+    options.proguard_file,
+    options.r_text_out,
+    options.srcjar_out,
+  ]
+  output_paths = [x for x in possible_output_paths if x]
+
+  # List python deps in input_strings rather than input_paths since the contents
+  # of them does not change what gets written to the depsfile.
+  input_strings = options.extra_res_packages + [
+    options.aapt_path,
+    options.android_sdk,
+    options.app_as_shared_lib,
+    options.custom_package,
+    options.include_all_resources,
+    options.non_constant_id,
+    options.shared_resources,
+    options.v14_skip,
+  ]
+
+  input_paths = [ options.android_manifest ]
+  input_paths.extend(options.dependencies_res_zips)
+  input_paths.extend(p for p in options.extra_r_text_files if os.path.exists(p))
+
+  for d in options.resource_dirs:
+    for root, _, filenames in os.walk(d):
+      input_paths.extend(os.path.join(root, f) for f in filenames)
+
+  build_utils.CallAndWriteDepfileIfStale(
+      lambda: _OnStaleMd5(options),
+      options,
+      input_paths=input_paths,
+      input_strings=input_strings,
+      output_paths=output_paths,
+      # TODO(agrieve): Remove R_dir when it's no longer used (used only by GYP).
+      force=options.R_dir)
 
 
 if __name__ == '__main__':
-  main()
+  main(sys.argv[1:])
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index 5127100..2484354 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -5,36 +5,14 @@
 # found in the LICENSE file.
 
 import optparse
+import os
 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)
+def _ParseOptions(args):
   parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
   parser.add_option('--proguard-path',
@@ -48,21 +26,48 @@
   parser.add_option('--is-test', action='store_true',
       help='If true, extra proguard options for instrumentation tests will be '
       'added.')
+  parser.add_option('--tested-apk-info', help='Path to the proguard .info file '
+      'for the tested apk')
   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)
+  classpath = []
+  for arg in options.classpath:
+    classpath += build_utils.ParseGypList(arg)
+  options.classpath = classpath
 
-  if options.depfile:
-    build_utils.WriteDepfile(
-        options.depfile,
-        inputs + build_utils.GetPythonDependencies())
+  return options
 
-  if options.stamp:
-    build_utils.Touch(options.stamp)
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  options = _ParseOptions(args)
+
+  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.tested_apk_info:
+    proguard.tested_apk_info(options.tested_apk_info)
+
+  classpath = list(set(options.classpath))
+  proguard.libraryjars(classpath)
+
+  input_paths = proguard.GetInputs()
+
+  build_utils.CallAndWriteDepfileIfStale(
+      proguard.CheckOutput,
+      options,
+      input_paths=input_paths,
+      input_strings=proguard.build(),
+      output_paths=[options.output_path])
 
 
 if __name__ == '__main__':
diff --git a/build/android/gyp/util/build_device.py b/build/android/gyp/util/build_device.py
index 7e0d57b..a19045b 100644
--- a/build/android/gyp/util/build_device.py
+++ b/build/android/gyp/util/build_device.py
@@ -16,11 +16,14 @@
 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
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.android.sdk import adb_wrapper
 
-GetAttachedDevices = android_commands.GetAttachedDevices
+
+def GetAttachedDevices():
+  return [a.GetDeviceSerial()
+          for a in adb_wrapper.AdbWrapper.Devices()]
 
 
 class BuildDevice(object):
@@ -42,13 +45,16 @@
   def Install(self, *args, **kwargs):
     return self.device.Install(*args, **kwargs)
 
+  def InstallSplitApk(self, *args, **kwargs):
+    return self.device.InstallSplitApk(*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
+    #   org.chromium.chrome.apk
     # -rw-r--r-- system   system    7376582 2013-04-19 16:34 \
-    #   org.chromium.chrome.shell-1.apk
+    #   org.chromium.chrome-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
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index 65b1a64..a8eb7c4 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -16,15 +16,19 @@
 import tempfile
 import zipfile
 
+# Some clients do not add //build/android/gyp to PYTHONPATH.
+import md5_check  # pylint: disable=relative-import
 
-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,
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+from pylib import constants
+
+COLORAMA_ROOT = os.path.join(constants.DIR_SOURCE_ROOT,
                              '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')
+_HERMETIC_TIMESTAMP = (2001, 1, 1, 0, 0, 0)
+_HERMETIC_FILE_ATTR = (0644 << 16L)
 
 
 @contextlib.contextmanager
@@ -194,7 +198,8 @@
     raise Exception('Absolute zip path: %s' % name)
 
 
-def ExtractAll(zip_path, path=None, no_clobber=True, pattern=None):
+def ExtractAll(zip_path, path=None, no_clobber=True, pattern=None,
+               predicate=None):
   if path is None:
     path = os.getcwd()
   elif not os.path.exists(path):
@@ -207,6 +212,8 @@
       if pattern is not None:
         if not fnmatch.fnmatch(name, pattern):
           continue
+      if predicate and not predicate(name):
+        continue
       CheckZipPath(name)
       if no_clobber:
         output_path = os.path.join(path, name)
@@ -214,43 +221,95 @@
           raise Exception(
               'Path already exists from zip: %s %s %s'
               % (zip_path, name, output_path))
-
-    z.extractall(path=path)
+      z.extract(name, path)
 
 
-def DoZip(inputs, output, base_dir):
+def AddToZipHermetic(zip_file, zip_path, src_path=None, data=None,
+                     compress=None):
+  """Adds a file to the given ZipFile with a hard-coded modified time.
+
+  Args:
+    zip_file: ZipFile instance to add the file to.
+    zip_path: Destination path within the zip file.
+    src_path: Path of the source file. Mutually exclusive with |data|.
+    data: File data as a string.
+    compress: Whether to enable compression. Default is take from ZipFile
+        constructor.
+  """
+  assert (src_path is None) != (data is None), (
+      '|src_path| and |data| are mutually exclusive.')
+  CheckZipPath(zip_path)
+  zipinfo = zipfile.ZipInfo(filename=zip_path, date_time=_HERMETIC_TIMESTAMP)
+  zipinfo.external_attr = _HERMETIC_FILE_ATTR
+
+  if src_path:
+    with file(src_path) as f:
+      data = f.read()
+
+  # zipfile will deflate even when it makes the file bigger. To avoid
+  # growing files, disable compression at an arbitrary cut off point.
+  if len(data) < 16:
+    compress = False
+
+  # None converts to ZIP_STORED, when passed explicitly rather than the
+  # default passed to the ZipFile constructor.
+  args = []
+  if compress is not None:
+    args.append(zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED)
+  zip_file.writestr(zipinfo, data, *args)
+
+
+def DoZip(inputs, output, base_dir=None):
+  """Creates a zip file from a list of files.
+
+  Args:
+    inputs: A list of paths to zip, or a list of (zip_path, fs_path) tuples.
+    output: Destination .zip file.
+    base_dir: Prefix to strip from inputs.
+  """
+  input_tuples = []
+  for tup in inputs:
+    if isinstance(tup, basestring):
+      tup = (os.path.relpath(tup, base_dir), tup)
+    input_tuples.append(tup)
+
+  # Sort by zip path to ensure stable zip ordering.
+  input_tuples.sort(key=lambda tup: tup[0])
   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))
+    for zip_path, fs_path in input_tuples:
+      AddToZipHermetic(outfile, zip_path, src_path=fs_path)
 
 
 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)
+  """Creates a zip file from a directory."""
+  inputs = []
+  for root, _, files in os.walk(base_dir):
+    for f in files:
+      inputs.append(os.path.join(root, f))
+  DoZip(inputs, output, base_dir)
 
 
-def MergeZips(output, inputs, exclude_patterns=None):
+def MatchesGlob(path, filters):
+  """Returns whether the given path matches any of the given glob patterns."""
+  return filters and any(fnmatch.fnmatch(path, f) for f in filters)
+
+
+def MergeZips(output, inputs, exclude_patterns=None, path_transform=None):
+  path_transform = path_transform or (lambda p, z: p)
   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)
+          # Ignore directories.
+          if name[-1] == '/':
+            continue
+          dst_name = path_transform(name, in_file)
+          already_added = dst_name in added_names
+          if not already_added and not MatchesGlob(dst_name, exclude_patterns):
+            AddToZipHermetic(out_zip, dst_name, data=in_zip.read(name))
+            added_names.add(dst_name)
 
 
 def PrintWarning(message):
@@ -310,8 +369,9 @@
 
   abs_module_paths = map(os.path.abspath, module_paths)
 
+  assert os.path.isabs(constants.DIR_SOURCE_ROOT)
   non_system_module_paths = [
-      p for p in abs_module_paths if p.startswith(CHROMIUM_SRC)]
+      p for p in abs_module_paths if p.startswith(constants.DIR_SOURCE_ROOT)]
   def ConvertPycToPy(s):
     if s.endswith('.pyc'):
       return s[:-1]
@@ -323,9 +383,13 @@
 
 
 def AddDepfileOption(parser):
-  parser.add_option('--depfile',
-                    help='Path to depfile. This must be specified as the '
-                    'action\'s first output.')
+  # TODO(agrieve): Get rid of this once we've moved to argparse.
+  if hasattr(parser, 'add_option'):
+    func = parser.add_option
+  else:
+    func = parser.add_argument
+  func('--depfile',
+       help='Path to depfile. Must be specified as the action\'s first output.')
 
 
 def WriteDepfile(path, dependencies):
@@ -374,3 +438,48 @@
 
   return new_args
 
+
+def CallAndWriteDepfileIfStale(function, options, record_path=None,
+                               input_paths=None, input_strings=None,
+                               output_paths=None, force=False,
+                               pass_changes=False):
+  """Wraps md5_check.CallAndRecordIfStale() and also writes dep & stamp files.
+
+  Depfiles and stamp files are automatically added to output_paths when present
+  in the |options| argument. They are then created after |function| is called.
+  """
+  if not output_paths:
+    raise Exception('At least one output_path must be specified.')
+  input_paths = list(input_paths or [])
+  input_strings = list(input_strings or [])
+  output_paths = list(output_paths or [])
+
+  python_deps = None
+  if hasattr(options, 'depfile') and options.depfile:
+    python_deps = GetPythonDependencies()
+    # List python deps in input_strings rather than input_paths since the
+    # contents of them does not change what gets written to the depfile.
+    input_strings += python_deps
+    output_paths += [options.depfile]
+
+  stamp_file = hasattr(options, 'stamp') and options.stamp
+  if stamp_file:
+    output_paths += [stamp_file]
+
+  def on_stale_md5(changes):
+    args = (changes,) if pass_changes else ()
+    function(*args)
+    if python_deps is not None:
+      WriteDepfile(options.depfile, python_deps + input_paths)
+    if stamp_file:
+      Touch(stamp_file)
+
+  md5_check.CallAndRecordIfStale(
+      on_stale_md5,
+      record_path=record_path,
+      input_paths=input_paths,
+      input_strings=input_strings,
+      output_paths=output_paths,
+      force=force,
+      pass_changes=True)
+
diff --git a/build/android/gyp/util/md5_check.py b/build/android/gyp/util/md5_check.py
index 9f365aa..7dac2e4 100644
--- a/build/android/gyp/util/md5_check.py
+++ b/build/android/gyp/util/md5_check.py
@@ -2,33 +2,352 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import difflib
 import hashlib
+import itertools
+import json
 import os
+import sys
+import zipfile
+
+
+# When set and a difference is detected, a diff of what changed is printed.
+PRINT_EXPLANATIONS = int(os.environ.get('PRINT_BUILD_EXPLANATIONS', 0))
+
+# An escape hatch that causes all targets to be rebuilt.
+_FORCE_REBUILD = int(os.environ.get('FORCE_REBUILD', 0))
 
 
 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.
+    output_paths=None, force=False, pass_changes=False):
+  """Calls function if outputs are stale.
 
-  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.
+  Outputs are considered stale if:
+  - any output_paths are missing, or
+  - the contents of any file within input_paths has changed, or
+  - the contents of input_strings has changed.
 
-  If force is True, the function will be called regardless of whether the
-  md5sum is out of date.
+  To debug which files are out-of-date, set the environment variable:
+      PRINT_MD5_DIFFS=1
+
+  Args:
+    function: The function to call.
+    record_path: Path to record metadata.
+      Defaults to output_paths[0] + '.md5.stamp'
+    input_paths: List of paths to calcualte an md5 sum on.
+    input_strings: List of strings to record verbatim.
+    output_paths: List of output paths.
+    force: Whether to treat outputs as missing regardless of whether they
+      actually are.
+    pass_changes: Whether to pass a Changes instance to |function|.
   """
-  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()
+  assert record_path or output_paths
+  input_paths = input_paths or []
+  input_strings = input_strings or []
+  output_paths = output_paths or []
+  record_path = record_path or output_paths[0] + '.md5.stamp'
+
+  assert record_path.endswith('.stamp'), (
+      'record paths must end in \'.stamp\' so that they are easy to find '
+      'and delete')
+
+  new_metadata = _Metadata()
+  new_metadata.AddStrings(input_strings)
+
+  for path in input_paths:
+    if _IsZipFile(path):
+      entries = _ExtractZipEntries(path)
+      new_metadata.AddZipFile(path, entries)
+    else:
+      new_metadata.AddFile(path, _Md5ForPath(path))
+
+  old_metadata = None
+  force = force or _FORCE_REBUILD
+  missing_outputs = [x for x in output_paths if force or not os.path.exists(x)]
+  # When outputs are missing, don't bother gathering change information.
+  if not missing_outputs and os.path.exists(record_path):
+    with open(record_path, 'r') as jsonfile:
+      try:
+        old_metadata = _Metadata.FromFile(jsonfile)
+      except:  # pylint: disable=bare-except
+        pass  # Not yet using new file format.
+
+  changes = Changes(old_metadata, new_metadata, force, missing_outputs)
+  if not changes.HasChanges():
+    return
+
+  if PRINT_EXPLANATIONS:
+    print '=' * 80
+    print 'Target is stale: %s' % record_path
+    print changes.DescribeDifference()
+    print '=' * 80
+
+  args = (changes,) if pass_changes else ()
+  function(*args)
+
+  with open(record_path, 'w') as f:
+    new_metadata.ToFile(f)
+
+
+class Changes(object):
+  """Provides and API for querying what changed between runs."""
+
+  def __init__(self, old_metadata, new_metadata, force, missing_outputs):
+    self.old_metadata = old_metadata
+    self.new_metadata = new_metadata
+    self.force = force
+    self.missing_outputs = missing_outputs
+
+  def _GetOldTag(self, path, subpath=None):
+    return self.old_metadata and self.old_metadata.GetTag(path, subpath)
+
+  def HasChanges(self):
+    """Returns whether any changes exist."""
+    return (self.force or
+            not self.old_metadata or
+            self.old_metadata.StringsMd5() != self.new_metadata.StringsMd5() or
+            self.old_metadata.FilesMd5() != self.new_metadata.FilesMd5())
+
+  def AddedOrModifiedOnly(self):
+    """Returns whether the only changes were from added or modified (sub)files.
+
+    No missing outputs, no removed paths/subpaths.
+    """
+    if (self.force or
+        not self.old_metadata or
+        self.old_metadata.StringsMd5() != self.new_metadata.StringsMd5()):
+      return False
+    if any(self.IterRemovedPaths()):
+      return False
+    for path in self.IterModifiedPaths():
+      if any(self.IterRemovedSubpaths(path)):
+        return False
+    return True
+
+  def IterAddedPaths(self):
+    """Generator for paths that were added."""
+    for path in self.new_metadata.IterPaths():
+      if self._GetOldTag(path) is None:
+        yield path
+
+  def IterAddedSubpaths(self, path):
+    """Generator for paths that were added within the given zip file."""
+    for subpath in self.new_metadata.IterSubpaths(path):
+      if self._GetOldTag(path, subpath) is None:
+        yield subpath
+
+  def IterRemovedPaths(self):
+    """Generator for paths that were removed."""
+    if self.old_metadata:
+      for path in self.old_metadata.IterPaths():
+        if self.new_metadata.GetTag(path) is None:
+          yield path
+
+  def IterRemovedSubpaths(self, path):
+    """Generator for paths that were removed within the given zip file."""
+    if self.old_metadata:
+      for subpath in self.old_metadata.IterSubpaths(path):
+        if self.new_metadata.GetTag(path, subpath) is None:
+          yield subpath
+
+  def IterModifiedPaths(self):
+    """Generator for paths whose contents have changed."""
+    for path in self.new_metadata.IterPaths():
+      old_tag = self._GetOldTag(path)
+      new_tag = self.new_metadata.GetTag(path)
+      if old_tag is not None and old_tag != new_tag:
+        yield path
+
+  def IterModifiedSubpaths(self, path):
+    """Generator for paths within a zip file whose contents have changed."""
+    for subpath in self.new_metadata.IterSubpaths(path):
+      old_tag = self._GetOldTag(path, subpath)
+      new_tag = self.new_metadata.GetTag(path, subpath)
+      if old_tag is not None and old_tag != new_tag:
+        yield subpath
+
+  def IterChangedPaths(self):
+    """Generator for all changed paths (added/removed/modified)."""
+    return itertools.chain(self.IterRemovedPaths(),
+                           self.IterModifiedPaths(),
+                           self.IterAddedPaths())
+
+  def IterChangedSubpaths(self, path):
+    """Generator for paths within a zip that were added/removed/modified."""
+    return itertools.chain(self.IterRemovedSubpaths(path),
+                           self.IterModifiedSubpaths(path),
+                           self.IterAddedSubpaths(path))
+
+  def DescribeDifference(self):
+    """Returns a human-readable description of what changed."""
+    if self.force:
+      return 'force=True'
+    elif self.missing_outputs:
+      return 'Outputs do not exist:\n  ' + '\n  '.join(self.missing_outputs)
+    elif self.old_metadata is None:
+      return 'Previous stamp file not found.'
+
+    if self.old_metadata.StringsMd5() != self.new_metadata.StringsMd5():
+      ndiff = difflib.ndiff(self.old_metadata.GetStrings(),
+                            self.new_metadata.GetStrings())
+      changed = [s for s in ndiff if not s.startswith(' ')]
+      return 'Input strings changed:\n  ' + '\n  '.join(changed)
+
+    if self.old_metadata.FilesMd5() == self.new_metadata.FilesMd5():
+      return "There's no difference."
+
+    lines = []
+    lines.extend('Added: ' + p for p in self.IterAddedPaths())
+    lines.extend('Removed: ' + p for p in self.IterRemovedPaths())
+    for path in self.IterModifiedPaths():
+      lines.append('Modified: ' + path)
+      lines.extend('  -> Subpath added: ' + p
+                   for p in self.IterAddedSubpaths(path))
+      lines.extend('  -> Subpath removed: ' + p
+                   for p in self.IterRemovedSubpaths(path))
+      lines.extend('  -> Subpath modified: ' + p
+                   for p in self.IterModifiedSubpaths(path))
+    if lines:
+      return 'Input files changed:\n  ' + '\n  '.join(lines)
+    return 'I have no idea what changed (there is a bug).'
+
+
+class _Metadata(object):
+  """Data model for tracking change metadata."""
+  # Schema:
+  # {
+  #   "files-md5": "VALUE",
+  #   "strings-md5": "VALUE",
+  #   "input-files": [
+  #     {
+  #       "path": "path.jar",
+  #       "tag": "{MD5 of entries}",
+  #       "entries": [
+  #         { "path": "org/chromium/base/Foo.class", "tag": "{CRC32}" }, ...
+  #       ]
+  #     }, {
+  #       "path": "path.txt",
+  #       "tag": "{MD5}",
+  #     }
+  #   ],
+  #   "input-strings": ["a", "b", ...],
+  # }
+  def __init__(self):
+    self._files_md5 = None
+    self._strings_md5 = None
+    self._files = []
+    self._strings = []
+    # Map of (path, subpath) -> entry. Created upon first call to _GetEntry().
+    self._file_map = None
+
+  @classmethod
+  def FromFile(cls, fileobj):
+    """Returns a _Metadata initialized from a file object."""
+    ret = cls()
+    obj = json.load(fileobj)
+    ret._files_md5 = obj['files-md5']
+    ret._strings_md5 = obj['strings-md5']
+    ret._files = obj['input-files']
+    ret._strings = obj['input-strings']
+    return ret
+
+  def ToFile(self, fileobj):
+    """Serializes metadata to the given file object."""
+    obj = {
+        "files-md5": self.FilesMd5(),
+        "strings-md5": self.StringsMd5(),
+        "input-files": self._files,
+        "input-strings": self._strings,
+    }
+    json.dump(obj, fileobj, indent=2)
+
+  def _AssertNotQueried(self):
+    assert self._files_md5 is None
+    assert self._strings_md5 is None
+    assert self._file_map is None
+
+  def AddStrings(self, values):
+    self._AssertNotQueried()
+    self._strings.extend(str(v) for v in values)
+
+  def AddFile(self, path, tag):
+    """Adds metadata for a non-zip file.
+
+    Args:
+      path: Path to the file.
+      tag: A short string representative of the file contents.
+    """
+    self._AssertNotQueried()
+    self._files.append({
+        'path': path,
+        'tag': tag,
+    })
+
+  def AddZipFile(self, path, entries):
+    """Adds metadata for a zip file.
+
+    Args:
+      path: Path to the file.
+      entries: List of (subpath, tag) tuples for entries within the zip.
+    """
+    self._AssertNotQueried()
+    tag = _ComputeInlineMd5(itertools.chain((e[0] for e in entries),
+                                            (e[1] for e in entries)))
+    self._files.append({
+        'path': path,
+        'tag': tag,
+        'entries': [{"path": e[0], "tag": e[1]} for e in entries],
+    })
+
+  def GetStrings(self):
+    """Returns the list of input strings."""
+    return self._strings
+
+  def FilesMd5(self):
+    """Lazily computes and returns the aggregate md5 of input files."""
+    if self._files_md5 is None:
+      # Omit paths from md5 since temporary files have random names.
+      self._files_md5 = _ComputeInlineMd5(
+          self.GetTag(p) for p in sorted(self.IterPaths()))
+    return self._files_md5
+
+  def StringsMd5(self):
+    """Lazily computes and returns the aggregate md5 of input strings."""
+    if self._strings_md5 is None:
+      self._strings_md5 = _ComputeInlineMd5(self._strings)
+    return self._strings_md5
+
+  def _GetEntry(self, path, subpath=None):
+    """Returns the JSON entry for the given path / subpath."""
+    if self._file_map is None:
+      self._file_map = {}
+      for entry in self._files:
+        self._file_map[(entry['path'], None)] = entry
+        for subentry in entry.get('entries', ()):
+          self._file_map[(entry['path'], subentry['path'])] = subentry
+    return self._file_map.get((path, subpath))
+
+  def GetTag(self, path, subpath=None):
+    """Returns the tag for the given path / subpath."""
+    ret = self._GetEntry(path, subpath)
+    return ret and ret['tag']
+
+  def IterPaths(self):
+    """Returns a generator for all top-level paths."""
+    return (e['path'] for e in self._files)
+
+  def IterSubpaths(self, path):
+    """Returns a generator for all subpaths in the given zip.
+
+    If the given path is not a zip file or doesn't exist, returns an empty
+    iterable.
+    """
+    outer_entry = self._GetEntry(path)
+    if not outer_entry:
+      return ()
+    subentries = outer_entry.get('entries', [])
+    return (entry['path'] for entry in subentries)
 
 
 def _UpdateMd5ForFile(md5, path, block_size=2**16):
@@ -46,41 +365,38 @@
       _UpdateMd5ForFile(md5, os.path.join(root, f))
 
 
-def _UpdateMd5ForPath(md5, path):
+def _Md5ForPath(path):
+  md5 = hashlib.md5()
   if os.path.isdir(path):
     _UpdateMd5ForDirectory(md5, path)
   else:
     _UpdateMd5ForFile(md5, path)
+  return md5.hexdigest()
 
 
-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 = []
+def _ComputeInlineMd5(iterable):
+  """Computes the md5 of the concatenated parameters."""
+  md5 = hashlib.md5()
+  for item in iterable:
+    md5.update(str(item))
+  return md5.hexdigest()
 
-    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
+def _IsZipFile(path):
+  """Returns whether to treat the given file as a zip file."""
+  # ijar doesn't set the CRC32 field.
+  if path.endswith('.interface.jar'):
+    return False
+  return path[-4:] in ('.zip', '.apk', '.jar') or path.endswith('.srcjar')
 
-    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)
+def _ExtractZipEntries(path):
+  """Returns a list of (path, CRC32) of all files within |path|."""
+  entries = []
+  with zipfile.ZipFile(path) as zip_file:
+    for zip_info in zip_file.infolist():
+      # Skip directories and empty files.
+      if zip_info.CRC:
+        entries.append(
+            (zip_info.filename, zip_info.CRC + zip_info.compress_type))
+  return entries
diff --git a/build/android/gyp/util/md5_check_test.py b/build/android/gyp/util/md5_check_test.py
old mode 100644
new mode 100755
index 4f89fc2..312d4a9
--- a/build/android/gyp/util/md5_check_test.py
+++ b/build/android/gyp/util/md5_check_test.py
@@ -1,65 +1,119 @@
+#!/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 tempfile
 import unittest
+import zipfile
 
 import md5_check # pylint: disable=W0403
 
 
+def _WriteZipFile(path, entries):
+  with zipfile.ZipFile(path, 'w') as zip_file:
+    for subpath, data in entries:
+      zip_file.writestr(subpath, data)
+
+
 class TestMd5Check(unittest.TestCase):
   def setUp(self):
     self.called = False
+    self.changes = None
 
   def testCallAndRecordIfStale(self):
     input_strings = ['string1', 'string2']
-    input_file1 = tempfile.NamedTemporaryFile()
-    input_file2 = tempfile.NamedTemporaryFile()
+    input_file1 = tempfile.NamedTemporaryFile(suffix='.txt')
+    input_file2 = tempfile.NamedTemporaryFile(suffix='.zip')
     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()
+    # Test out empty zip file to start.
+    _WriteZipFile(input_file2.name, [])
     input_files = [input_file1.name, input_file2.name]
 
     record_path = tempfile.NamedTemporaryFile(suffix='.stamp')
 
-    def CheckCallAndRecord(should_call, message, force=False):
+    def CheckCallAndRecord(should_call, message, force=False,
+                           outputs_specified=False, outputs_missing=False,
+                           expected_changes=None, added_or_modified_only=None):
+      output_paths = None
+      if outputs_specified:
+        output_file1 = tempfile.NamedTemporaryFile()
+        if outputs_missing:
+          output_file1.close()  # Gets deleted on close().
+        output_paths = [output_file1.name]
+
       self.called = False
-      def MarkCalled():
-        self.called = True
+      self.changes = None
+      if expected_changes or added_or_modified_only is not None:
+        def MarkCalled(changes):
+          self.called = True
+          self.changes = changes
+      else:
+        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)
+          output_paths=output_paths,
+          force=force,
+          pass_changes=(expected_changes or added_or_modified_only) is not None)
+      self.assertEqual(should_call, self.called, message)
+      if expected_changes:
+        description = self.changes.DescribeDifference()
+        self.assertTrue(fnmatch.fnmatch(description, expected_changes),
+                        'Expected %s to match %s' % (
+                        repr(description), repr(expected_changes)))
+      if should_call and added_or_modified_only is not None:
+        self.assertEqual(added_or_modified_only,
+                         self.changes.AddedOrModifiedOnly())
 
-    CheckCallAndRecord(True, 'should call when record doesn\'t exist')
+    CheckCallAndRecord(True, 'should call when record doesn\'t exist',
+                       expected_changes='Previous stamp file not found.',
+                       added_or_modified_only=False)
     CheckCallAndRecord(False, 'should not call when nothing changed')
-    CheckCallAndRecord(True, force=True, message='should call when forced')
+    CheckCallAndRecord(False, 'should not call when nothing changed #2',
+                       outputs_specified=True, outputs_missing=False)
+    CheckCallAndRecord(True, 'should call when output missing',
+                       outputs_specified=True, outputs_missing=True,
+                       expected_changes='Outputs do not exist:*',
+                       added_or_modified_only=False)
+    CheckCallAndRecord(True, force=True, message='should call when forced',
+                       expected_changes='force=True',
+                       added_or_modified_only=False)
 
     input_file1.write('some more input')
     input_file1.flush()
-    CheckCallAndRecord(True, 'changed input file should trigger call')
+    CheckCallAndRecord(True, 'changed input file should trigger call',
+                       expected_changes='*Modified: %s' % input_file1.name,
+                       added_or_modified_only=True)
 
     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')
+    CheckCallAndRecord(True, 'removing file should trigger call',
+                       expected_changes='*Removed: %s' % input_file1.name,
+                       added_or_modified_only=False)
 
-    input_files.append(input_file2.name)
-    CheckCallAndRecord(True, 'added input file should trigger call')
+    input_files.append(input_file1.name)
+    CheckCallAndRecord(True, 'added input file should trigger call',
+                       expected_changes='*Added: %s' % input_file1.name,
+                       added_or_modified_only=True)
 
     input_strings[0] = input_strings[0] + ' a bit longer'
-    CheckCallAndRecord(True, 'changed input string should trigger call')
+    CheckCallAndRecord(True, 'changed input string should trigger call',
+                       expected_changes='*Input strings changed*',
+                       added_or_modified_only=False)
 
     input_strings = input_strings[::-1]
-    CheckCallAndRecord(True, 'reordering of string inputs should trigger call')
+    CheckCallAndRecord(True, 'reordering of string inputs should trigger call',
+                       expected_changes='*Input strings changed*')
 
     input_strings = input_strings[:1]
     CheckCallAndRecord(True, 'removing a string should trigger call')
@@ -67,6 +121,24 @@
     input_strings.append('a brand new string')
     CheckCallAndRecord(True, 'added input string should trigger call')
 
+    _WriteZipFile(input_file2.name, [('path/1.txt', '1')])
+    CheckCallAndRecord(True, 'added subpath should trigger call',
+                       expected_changes='*Modified: %s*Subpath added: %s' % (
+                                        input_file2.name, 'path/1.txt'),
+                       added_or_modified_only=True)
+    _WriteZipFile(input_file2.name, [('path/1.txt', '2')])
+    CheckCallAndRecord(True, 'changed subpath should trigger call',
+                       expected_changes='*Modified: %s*Subpath modified: %s' % (
+                                        input_file2.name, 'path/1.txt'),
+                       added_or_modified_only=True)
+    CheckCallAndRecord(False, 'should not call when nothing changed')
+
+    _WriteZipFile(input_file2.name, [])
+    CheckCallAndRecord(True, 'removed subpath should trigger call',
+                       expected_changes='*Modified: %s*Subpath removed: %s' % (
+                                        input_file2.name, 'path/1.txt'),
+                       added_or_modified_only=False)
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/build/android/gyp/util/proguard_util.py b/build/android/gyp/util/proguard_util.py
index 901cd9f..8ca8646 100644
--- a/build/android/gyp/util/proguard_util.py
+++ b/build/android/gyp/util/proguard_util.py
@@ -32,45 +32,55 @@
   def __init__(self, proguard_jar):
     assert os.path.exists(proguard_jar)
     self._proguard_jar_path = proguard_jar
-    self._test = None
+    self._tested_apk_info_path = None
+    self._tested_apk_info = None
     self._mapping = None
     self._libraries = None
     self._injars = None
     self._configs = None
     self._outjar = None
+    self._cmd = None
 
   def outjar(self, path):
+    assert self._cmd is None
     assert self._outjar is None
     self._outjar = path
 
-  def is_test(self, enable):
-    assert self._test is None
-    self._test = enable
+  def tested_apk_info(self, tested_apk_info_path):
+    assert self._cmd is None
+    assert self._tested_apk_info is None
+    self._tested_apk_info_path = tested_apk_info_path
 
   def mapping(self, path):
+    assert self._cmd is None
     assert self._mapping is None
     assert os.path.exists(path), path
     self._mapping = path
 
   def libraryjars(self, paths):
+    assert self._cmd is None
     assert self._libraries is None
     for p in paths:
       assert os.path.exists(p), p
     self._libraries = paths
 
   def injars(self, paths):
+    assert self._cmd is None
     assert self._injars is None
     for p in paths:
       assert os.path.exists(p), p
     self._injars = paths
 
   def configs(self, paths):
+    assert self._cmd is None
     assert self._configs is None
     for p in paths:
       assert os.path.exists(p), p
     self._configs = paths
 
   def build(self):
+    if self._cmd:
+      return self._cmd
     assert self._injars is not None
     assert self._outjar is not None
     assert self._configs is not None
@@ -78,7 +88,16 @@
       'java', '-jar', self._proguard_jar_path,
       '-forceprocessing',
     ]
-    if self._test:
+    if self._tested_apk_info_path:
+      assert len(self._configs) == 1
+      tested_apk_info = build_utils.ReadJson(self._tested_apk_info_path)
+      self._configs += tested_apk_info['configs']
+      self._injars = [
+          p for p in self._injars if not p in tested_apk_info['inputs']]
+      if not self._libraries:
+        self._libraries = []
+      self._libraries += tested_apk_info['inputs']
+      self._mapping = tested_apk_info['mapping']
       cmd += [
         '-dontobfuscate',
         '-dontoptimize',
@@ -111,18 +130,38 @@
       '-printusage', self._outjar + '.usage',
       '-printmapping', self._outjar + '.mapping',
     ]
-    return cmd
+    self._cmd = cmd
+    return self._cmd
 
   def GetInputs(self):
+    self.build()
     inputs = [self._proguard_jar_path] + self._configs + self._injars
     if self._mapping:
       inputs.append(self._mapping)
     if self._libraries:
       inputs += self._libraries
+    if self._tested_apk_info_path:
+      inputs += [self._tested_apk_info_path]
     return inputs
 
 
   def CheckOutput(self):
-    build_utils.CheckOutput(self.build(), print_stdout=True,
+    self.build()
+    # Proguard will skip writing these files if they would be empty. Create
+    # empty versions of them all now so that they are updated as the build
+    # expects.
+    open(self._outjar + '.dump', 'w').close()
+    open(self._outjar + '.seeds', 'w').close()
+    open(self._outjar + '.usage', 'w').close()
+    open(self._outjar + '.mapping', 'w').close()
+    build_utils.CheckOutput(self._cmd, print_stdout=True,
                             stdout_filter=FilterProguardOutput)
 
+    this_info = {
+      'inputs': self._injars,
+      'configs': self._configs,
+      'mapping': self._outjar + '.mapping',
+    }
+
+    build_utils.WriteJson(this_info, self._outjar + '.info')
+
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 8507a95..b8b8ec8 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -26,12 +26,14 @@
     b. the files are added to the action's depfile
 """
 
+import itertools
 import optparse
 import os
 import sys
 import xml.dom.minidom
 
 from util import build_utils
+from util import md5_check
 
 import write_ordered_libraries
 
@@ -107,6 +109,40 @@
     return self.all_deps_config_paths
 
 
+def _MergeAssets(all_assets):
+  """Merges all assets from the given deps.
+
+  Returns:
+    A tuple of lists: (compressed, uncompressed)
+    Each tuple entry is a list of "srcPath:zipPath". srcPath is the path of the
+    asset to add, and zipPath is the location within the zip (excluding assets/
+    prefix)
+  """
+  compressed = {}
+  uncompressed = {}
+  for asset_dep in all_assets:
+    entry = asset_dep['assets']
+    disable_compression = entry.get('disable_compression', False)
+    dest_map = uncompressed if disable_compression else compressed
+    other_map = compressed if disable_compression else uncompressed
+    outputs = entry.get('outputs', [])
+    for src, dest in itertools.izip_longest(entry['sources'], outputs):
+      if not dest:
+        dest = os.path.basename(src)
+      # Merge so that each path shows up in only one of the lists, and that
+      # deps of the same target override previous ones.
+      other_map.pop(dest, 0)
+      dest_map[dest] = src
+
+  def create_list(asset_map):
+    ret = ['%s:%s' % (src, dest) for dest, src in asset_map.iteritems()]
+    # Sort to ensure deterministic ordering.
+    ret.sort()
+    return ret
+
+  return create_list(compressed), create_list(uncompressed)
+
+
 def main(argv):
   parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
@@ -128,6 +164,15 @@
       help='Java package name for these resources.')
   parser.add_option('--android-manifest', help='Path to android manifest.')
 
+  # android_assets options
+  parser.add_option('--asset-sources', help='List of asset sources.')
+  parser.add_option('--asset-renaming-sources',
+                    help='List of asset sources with custom destinations.')
+  parser.add_option('--asset-renaming-destinations',
+                    help='List of asset custom destinations.')
+  parser.add_option('--disable-asset-compression', action='store_true',
+                    help='Whether to disable asset compression.')
+
   # java library options
   parser.add_option('--jar-path', help='Path to target\'s jar output.')
   parser.add_option('--supports-android', action='store_true',
@@ -144,27 +189,34 @@
   parser.add_option('--native-libs', help='List of top-level native libs.')
   parser.add_option('--readelf-path', help='Path to toolchain\'s readelf.')
 
+  # apk options
+  parser.add_option('--apk-path', help='Path to the target\'s apk output.')
+
   parser.add_option('--tested-apk-config',
       help='Path to the build config of the tested apk (for an instrumentation '
       'test apk).')
+  parser.add_option('--proguard-enabled', action='store_true',
+      help='Whether proguard is enabled for this apk.')
+  parser.add_option('--proguard-info',
+      help='Path to the proguard .info output for this 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']:
+  required_options_map = {
+      'java_library': ['build_config', 'jar_path'],
+      'android_assets': ['build_config'],
+      'android_resources': ['build_config', 'resources_zip'],
+      'android_apk': ['build_config', 'jar_path', 'dex_path', 'resources_zip'],
+      'deps_dex': ['build_config', 'dex_path'],
+      'resource_rewriter': ['build_config']
+  }
+  required_options = required_options_map.get(options.type)
+  if not required_options:
     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')
 
@@ -181,7 +233,8 @@
   possible_deps_config_paths = build_utils.ParseGypList(
       options.possible_deps_configs)
 
-  allow_unknown_deps = options.type == 'android_apk'
+  allow_unknown_deps = (options.type in
+                        ('android_apk', 'android_assets', 'android_resources'))
   unknown_deps = [
       c for c in possible_deps_config_paths if not os.path.exists(c)]
   if unknown_deps and not allow_unknown_deps:
@@ -241,6 +294,8 @@
     deps_info['jar_path'] = options.jar_path
     if options.type == 'android_apk' or options.supports_android:
       deps_info['dex_path'] = options.dex_path
+    if options.type == 'android_apk':
+      deps_info['apk_path'] = options.apk_path
     config['javac'] = {
       'classpath': javac_classpath,
     }
@@ -260,6 +315,23 @@
     # Apks will get their resources srcjar explicitly passed to the java step.
     config['javac']['srcjars'] = []
 
+  if options.type == 'android_assets':
+    all_asset_sources = []
+    if options.asset_renaming_sources:
+      all_asset_sources.extend(
+          build_utils.ParseGypList(options.asset_renaming_sources))
+    if options.asset_sources:
+      all_asset_sources.extend(build_utils.ParseGypList(options.asset_sources))
+
+    deps_info['assets'] = {
+        'sources': all_asset_sources
+    }
+    if options.asset_renaming_destinations:
+      deps_info['assets']['outputs'] = (
+          build_utils.ParseGypList(options.asset_renaming_destinations))
+    if options.disable_asset_compression:
+      deps_info['assets']['disable_compression'] = True
+
   if options.type == 'android_resources':
     deps_info['resources_zip'] = options.resources_zip
     if options.srcjar:
@@ -272,14 +344,14 @@
     if options.r_text:
       deps_info['r_text'] = options.r_text
 
-  if options.type == 'android_resources' or options.type == 'android_apk':
+  if options.type in ('android_resources','android_apk', 'resource_rewriter'):
     config['resources'] = {}
     config['resources']['dependency_zips'] = [
         c['resources_zip'] for c in all_resources_deps]
     config['resources']['extra_package_names'] = []
     config['resources']['extra_r_text_files'] = []
 
-  if options.type == 'android_apk':
+  if options.type == 'android_apk' or options.type == 'resource_rewriter':
     config['resources']['extra_package_names'] = [
         c['package_name'] for c in all_resources_deps if 'package_name' in c]
     config['resources']['extra_r_text_files'] = [
@@ -288,6 +360,17 @@
   if options.type in ['android_apk', 'deps_dex']:
     deps_dex_files = [c['dex_path'] for c in all_library_deps]
 
+  proguard_enabled = options.proguard_enabled
+  if options.type == 'android_apk':
+    deps_info['proguard_enabled'] = proguard_enabled
+
+  if proguard_enabled:
+    deps_info['proguard_info'] = options.proguard_info
+    config['proguard'] = {}
+    proguard_config = config['proguard']
+    proguard_config['input_paths'] = [options.jar_path] + java_full_classpath
+    proguard_config['tested_apk_info'] = ''
+
   # 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:
@@ -301,12 +384,17 @@
     expected_tested_package = tested_apk_config['package_name']
     AndroidManifest(options.android_manifest).CheckInstrumentation(
         expected_tested_package)
+    if tested_apk_config['proguard_enabled']:
+      assert proguard_enabled, ('proguard must be enabled for instrumentation'
+          ' apks if it\'s enabled for the tested apk')
+      proguard_config['tested_apk_info'] = tested_apk_config['proguard_info']
+
+    deps_info['tested_apk_path'] = tested_apk_config['apk_path']
 
   # 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':
@@ -322,27 +410,42 @@
       manifest.CheckInstrumentation(manifest.GetPackageName())
 
     library_paths = []
-    java_libraries_list = []
-    if options.native_libs:
-      libraries = build_utils.ParseGypList(options.native_libs)
-      if libraries:
+    java_libraries_list_holder = [None]
+    libraries = build_utils.ParseGypList(options.native_libs or '[]')
+    if libraries:
+      def recompute_ordered_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 = (
+        all_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)
+        java_libraries_list_holder[0] = ('{%s}' % ','.join(
+            ['"%s"' % s[3:-3] for s in all_deps]))
+        library_paths.extend(
+            write_ordered_libraries.FullLibraryPath(x) for x in all_deps)
 
-      config['native'] = {
-        'libraries': library_paths,
-        'java_libraries_list': java_libraries_list
-      }
+      # This step takes about 600ms on a z620 for chrome_apk, so it's worth
+      # caching.
+      md5_check.CallAndRecordIfStale(
+          recompute_ordered_libraries,
+          record_path=options.build_config + '.nativelibs.md5.stamp',
+          input_paths=libraries,
+          output_paths=[options.build_config])
+      if not library_paths:
+        prev_config = build_utils.ReadJson(options.build_config)
+        java_libraries_list_holder[0] = (
+            prev_config['native']['java_libraries_list'])
+        library_paths.extend(prev_config['native']['libraries'])
+
+    config['native'] = {
+      'libraries': library_paths,
+      'java_libraries_list': java_libraries_list_holder[0],
+    }
+    config['assets'], config['uncompressed_assets'] = (
+        _MergeAssets(deps.All('android_assets')))
 
   build_utils.WriteJson(config, options.build_config, only_if_changed=True)
 
diff --git a/build/android/gyp/write_ordered_libraries.py b/build/android/gyp/write_ordered_libraries.py
index 67e7805..0fc9a8c 100755
--- a/build/android/gyp/write_ordered_libraries.py
+++ b/build/android/gyp/write_ordered_libraries.py
@@ -73,7 +73,7 @@
 
 
 def GetNonSystemDependencies(library_name):
-  all_deps = GetDependencies(FullLibraryPath(library_name))
+  all_deps = GetDependencies(library_name)
   return set((lib for lib in all_deps if not IsSystemLibrary(lib)))
 
 
@@ -119,8 +119,13 @@
   java_libraries_list = (
       '{%s}' % ','.join(['"%s"' % s[3:-3] for s in libraries]))
 
+  out_json = {
+      'libraries': libraries,
+      'lib_paths': [FullLibraryPath(l) for l in libraries],
+      'java_libraries_list': java_libraries_list
+      }
   build_utils.WriteJson(
-      {'libraries': libraries, 'java_libraries_list': java_libraries_list},
+      out_json,
       options.output,
       only_if_changed=True)
 
diff --git a/build/android/host_heartbeat.py b/build/android/host_heartbeat.py
index 6a7cdd1..ced24b2 100755
--- a/build/android/host_heartbeat.py
+++ b/build/android/host_heartbeat.py
@@ -12,14 +12,14 @@
 import sys
 import time
 
-from pylib.device import device_utils
+from devil.android import device_utils
 
 PULSE_PERIOD = 20
 
 def main():
   while True:
     try:
-      devices = device_utils.DeviceUtils.HealthyDevices()
+      devices = device_utils.DeviceUtils.HealthyDevices(blacklist=None)
       for d in devices:
         d.RunShellCommand(['touch', '/sdcard/host_heartbeat'],
                           check_return=True)
diff --git a/build/android/increase_size_for_speed.gypi b/build/android/increase_size_for_speed.gypi
index 48d17f5..c5600b1 100644
--- a/build/android/increase_size_for_speed.gypi
+++ b/build/android/increase_size_for_speed.gypi
@@ -18,17 +18,17 @@
               'cflags!': ['-Os'],
               'cflags': ['-O2'],
             }],
-            # Do not merge -Os and -O2 in LTO.
+            # Do not merge -Os and -O2 in GCC 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', {
+            ['OS=="android" and clang==0 and use_lto==1', {
               'cflags!': [
                 '-flto',
                 '-ffat-lto-objects',
               ],
             }],
-            ['OS=="android" and use_lto_o2==1', {
+            ['OS=="android" and clang==0 and use_lto_o2==1', {
               'cflags': [
                 '-flto',
                 '-ffat-lto-objects',
diff --git a/build/android/incremental_install/BUILD.gn b/build/android/incremental_install/BUILD.gn
new file mode 100644
index 0000000..ab39e4c
--- /dev/null
+++ b/build/android/incremental_install/BUILD.gn
@@ -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.
+
+import("//build/config/android/rules.gni")
+
+android_library("bootstrap_java") {
+  # Use .dex rather than .dex.jar to be usable by package_apk().
+  dex_path = "$target_gen_dir/bootstrap.dex"
+  java_files = [
+    "java/org/chromium/incrementalinstall/BootstrapApplication.java",
+    "java/org/chromium/incrementalinstall/BootstrapInstrumentation.java",
+    "java/org/chromium/incrementalinstall/ClassLoaderPatcher.java",
+    "java/org/chromium/incrementalinstall/LockFile.java",
+    "java/org/chromium/incrementalinstall/Reflect.java",
+  ]
+}
diff --git a/build/android/pylib/uiautomator/__init__.py b/build/android/incremental_install/__init__.py
similarity index 61%
rename from build/android/pylib/uiautomator/__init__.py
rename to build/android/incremental_install/__init__.py
index cda7672..1aaf0e1 100644
--- a/build/android/pylib/uiautomator/__init__.py
+++ b/build/android/incremental_install/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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/incremental_install/create_install_script.py b/build/android/incremental_install/create_install_script.py
new file mode 100755
index 0000000..3de4ed6
--- /dev/null
+++ b/build/android/incremental_install/create_install_script.py
@@ -0,0 +1,153 @@
+#!/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.
+
+"""Creates a script to run an "_incremental" .apk."""
+
+import argparse
+import os
+import pprint
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'gyp'))
+
+from pylib import constants
+from util import build_utils
+
+
+SCRIPT_TEMPLATE = """\
+#!/usr/bin/env python
+#
+# This file was generated by:
+#     //build/android/incremental_install/create_install_script.py
+
+import os
+import subprocess
+import sys
+
+
+def _ResolvePath(path):
+  script_directory = os.path.dirname(__file__)
+  return os.path.abspath(os.path.join(script_directory, path))
+
+
+# Exported to allow test runner to be able to install incremental apks.
+def GetInstallParameters():
+  apk_path = {apk_path}
+  native_libs = {native_libs}
+  dex_files = {dex_files}
+  splits = {splits}
+  show_proguard_warning = {show_proguard_warning}
+
+  return dict(apk_path=_ResolvePath(apk_path),
+              dex_files=[_ResolvePath(p) for p in dex_files],
+              native_libs=[_ResolvePath(p) for p in native_libs],
+              show_proguard_warning=show_proguard_warning,
+              splits=[_ResolvePath(p) for p in splits])
+
+
+def main():
+  output_directory = {output_directory}
+  cmd_path = {cmd_path}
+  params = GetInstallParameters()
+  cmd_args = [
+      _ResolvePath(cmd_path),
+      '--output-directory', _ResolvePath(output_directory),
+  ]
+  for native_lib in params['native_libs']:
+    cmd_args.extend(('--native_lib', native_lib))
+  for dex_path in params['dex_files']:
+    cmd_args.extend(('--dex-file', dex_path))
+  for split in params['splits']:
+    cmd_args.extend(('--split', split))
+  cmd_args.append(params['apk_path'])
+  if params['show_proguard_warning']:
+    cmd_args.append('--show-proguard-warning')
+  return subprocess.call(cmd_args + sys.argv[1:])
+
+if __name__ == '__main__':
+  sys.exit(main())
+"""
+
+
+def _ParseArgs(args):
+  args = build_utils.ExpandFileArgs(args)
+  parser = argparse.ArgumentParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_argument('--script-output-path',
+                      help='Output path for executable script.',
+                      required=True)
+  parser.add_argument('--output-directory',
+                      help='Path to the root build directory.',
+                      default='.')
+  parser.add_argument('--apk-path',
+                      help='Path to the .apk to install.',
+                      required=True)
+  parser.add_argument('--split',
+                      action='append',
+                      dest='splits',
+                      default=[],
+                      help='A glob matching the apk splits. '
+                           'Can be specified multiple times.')
+  parser.add_argument('--native-libs',
+                      action='append',
+                      default=[],
+                      help='GYP-list of paths to native libraries. Can be '
+                      'repeated.')
+  parser.add_argument('--dex-file',
+                      action='append',
+                      default=[],
+                      dest='dex_files',
+                      help='List of dex files to include.')
+  parser.add_argument('--dex-file-list',
+                      help='GYP-list of dex files.')
+  parser.add_argument('--show-proguard-warning',
+                      action='store_true',
+                      default=False,
+                      help='Print a warning about proguard being disabled')
+
+  options = parser.parse_args(args)
+  options.dex_files += build_utils.ParseGypList(options.dex_file_list)
+  all_libs = []
+  for gyp_list in options.native_libs:
+    all_libs.extend(build_utils.ParseGypList(gyp_list))
+  options.native_libs = all_libs
+  return options
+
+
+def main(args):
+  options = _ParseArgs(args)
+
+  def relativize(path):
+    script_dir = os.path.dirname(options.script_output_path)
+    return path and os.path.relpath(path, script_dir)
+
+  installer_path = os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android',
+                                'incremental_install', 'installer.py')
+  pformat = pprint.pformat
+  template_args = {
+      'cmd_path': pformat(relativize(installer_path)),
+      'apk_path': pformat(relativize(options.apk_path)),
+      'output_directory': pformat(relativize(options.output_directory)),
+      'native_libs': pformat([relativize(p) for p in options.native_libs]),
+      'dex_files': pformat([relativize(p) for p in options.dex_files]),
+      'show_proguard_warning': pformat(options.show_proguard_warning),
+      'splits': pformat([relativize(p) for p in options.splits]),
+  }
+
+  with open(options.script_output_path, 'w') as script:
+    script.write(SCRIPT_TEMPLATE.format(**template_args))
+
+  os.chmod(options.script_output_path, 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/incremental_install/generate_android_manifest.py b/build/android/incremental_install/generate_android_manifest.py
new file mode 100755
index 0000000..163b4c3
--- /dev/null
+++ b/build/android/incremental_install/generate_android_manifest.py
@@ -0,0 +1,110 @@
+#!/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.
+"""Creates an AndroidManifest.xml for an incremental APK.
+
+Given the manifest file for the real APK, generates an AndroidManifest.xml with
+the application class changed to IncrementalApplication.
+"""
+
+import argparse
+import os
+import sys
+from xml.etree import ElementTree
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.path.pardir, 'gyp'))
+from util import build_utils
+
+_ANDROID_NAMESPACE = 'http://schemas.android.com/apk/res/android'
+ElementTree.register_namespace('android', _ANDROID_NAMESPACE)
+
+_INCREMENTAL_APP_NAME = 'org.chromium.incrementalinstall.BootstrapApplication'
+_META_DATA_APP_NAME = 'incremental-install-real-app'
+_META_DATA_INSTRUMENTATION_NAME = 'incremental-install-real-instrumentation'
+_DEFAULT_APPLICATION_CLASS = 'android.app.Application'
+_DEFAULT_INSTRUMENTATION_CLASS = 'android.app.Instrumentation'
+
+
+def _AddNamespace(name):
+  """Adds the android namespace prefix to the given identifier."""
+  return '{%s}%s' % (_ANDROID_NAMESPACE, name)
+
+def _ParseArgs():
+  parser = argparse.ArgumentParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_argument('--src-manifest',
+                      help='The main manifest of the app',
+                      required=True)
+  parser.add_argument('--out-manifest',
+                      help='The output manifest',
+                      required=True)
+  parser.add_argument('--disable-isolated-processes',
+                      help='Changes all android:isolatedProcess to false. '
+                           'This is required on Android M+',
+                      action='store_true')
+  return parser.parse_args()
+
+
+def _CreateMetaData(parent, name, value):
+  meta_data_node = ElementTree.SubElement(parent, 'meta-data')
+  meta_data_node.set(_AddNamespace('name'), name)
+  meta_data_node.set(_AddNamespace('value'), value)
+
+
+def _ProcessManifest(main_manifest, disable_isolated_processes):
+  """Returns a transformed AndroidManifest.xml for use with _incremental apks.
+
+  Args:
+    main_manifest: Manifest contents to transform.
+    disable_isolated_processes: Whether to set all isolatedProcess attributes to
+        false
+
+  Returns:
+    The transformed AndroidManifest.xml.
+  """
+  if disable_isolated_processes:
+    main_manifest = main_manifest.replace('isolatedProcess="true"',
+                                          'isolatedProcess="false"')
+
+  doc = ElementTree.fromstring(main_manifest)
+  app_node = doc.find('application')
+  if app_node is None:
+    app_node = ElementTree.SubElement(doc, 'application')
+
+  real_app_class = app_node.get(_AddNamespace('name'),
+                                _DEFAULT_APPLICATION_CLASS)
+  app_node.set(_AddNamespace('name'), _INCREMENTAL_APP_NAME)
+  _CreateMetaData(app_node, _META_DATA_APP_NAME, real_app_class)
+
+  # Seems to be a bug in ElementTree, as doc.find() doesn't work here.
+  instrumentation_nodes = doc.findall('instrumentation')
+  if instrumentation_nodes:
+    instrumentation_node = instrumentation_nodes[0]
+    real_instrumentation_class = instrumentation_node.get(_AddNamespace('name'))
+    instrumentation_node.set(_AddNamespace('name'),
+                             _DEFAULT_INSTRUMENTATION_CLASS)
+    _CreateMetaData(app_node, _META_DATA_INSTRUMENTATION_NAME,
+                    real_instrumentation_class)
+
+  return ElementTree.tostring(doc, encoding='UTF-8')
+
+
+def main():
+  options = _ParseArgs()
+  with open(options.src_manifest) as f:
+    main_manifest_data = f.read()
+  new_manifest_data = _ProcessManifest(main_manifest_data,
+                                       options.disable_isolated_processes)
+  with open(options.out_manifest, 'w') as f:
+    f.write(new_manifest_data)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        [options.src_manifest] + build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/android/incremental_install/installer.py b/build/android/incremental_install/installer.py
new file mode 100755
index 0000000..e418cdb
--- /dev/null
+++ b/build/android/incremental_install/installer.py
@@ -0,0 +1,286 @@
+#!/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.
+
+"""Install *_incremental.apk targets as well as their dependent files."""
+
+import argparse
+import glob
+import logging
+import os
+import posixpath
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from devil.android import apk_helper
+from devil.android import device_utils
+from devil.android import device_errors
+from devil.android.sdk import version_codes
+from devil.utils import reraiser_thread
+from pylib import constants
+from pylib.utils import run_tests_helper
+from pylib.utils import time_profile
+
+prev_sys_path = list(sys.path)
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir, 'gyp'))
+from util import build_utils
+sys.path = prev_sys_path
+
+
+def _TransformDexPaths(paths):
+  """Given paths like ["/a/b/c", "/a/c/d"], returns ["b.c", "c.d"]."""
+  if len(paths) == 1:
+    return [os.path.basename(paths[0])]
+
+  prefix_len = len(os.path.commonprefix(paths))
+  return [p[prefix_len:].replace(os.sep, '.') for p in paths]
+
+
+def _Execute(concurrently, *funcs):
+  """Calls all functions in |funcs| concurrently or in sequence."""
+  timer = time_profile.TimeProfile()
+  if concurrently:
+    reraiser_thread.RunAsync(funcs)
+  else:
+    for f in funcs:
+      f()
+  timer.Stop(log=False)
+  return timer
+
+
+def _GetDeviceIncrementalDir(package):
+  """Returns the device path to put incremental files for the given package."""
+  return '/data/local/tmp/incremental-app-%s' % package
+
+
+def Uninstall(device, package):
+  """Uninstalls and removes all incremental files for the given package."""
+  main_timer = time_profile.TimeProfile()
+  device.Uninstall(package)
+  device.RunShellCommand(['rm', '-rf', _GetDeviceIncrementalDir(package)],
+                         check_return=True)
+  logging.info('Uninstall took %s seconds.', main_timer.GetDelta())
+
+
+def Install(device, apk, split_globs=None, native_libs=None, dex_files=None,
+            enable_device_cache=True, use_concurrency=True,
+            show_proguard_warning=False):
+  """Installs the given incremental apk and all required supporting files.
+
+  Args:
+    device: A DeviceUtils instance.
+    apk: The path to the apk, or an ApkHelper instance.
+    split_globs: Glob patterns for any required apk splits (optional).
+    native_libs: List of app's native libraries (optional).
+    dex_files: List of .dex.jar files that comprise the app's Dalvik code.
+    enable_device_cache: Whether to enable on-device caching of checksums.
+    use_concurrency: Whether to speed things up using multiple threads.
+    show_proguard_warning: Whether to print a warning about Proguard not being
+        enabled after installing.
+  """
+  main_timer = time_profile.TimeProfile()
+  install_timer = time_profile.TimeProfile()
+  push_native_timer = time_profile.TimeProfile()
+  push_dex_timer = time_profile.TimeProfile()
+
+  apk = apk_helper.ToHelper(apk)
+  apk_package = apk.GetPackageName()
+  device_incremental_dir = _GetDeviceIncrementalDir(apk_package)
+
+  # Install .apk(s) if any of them have changed.
+  def do_install():
+    install_timer.Start()
+    if split_globs:
+      splits = []
+      for split_glob in split_globs:
+        splits.extend((f for f in glob.glob(split_glob)))
+      device.InstallSplitApk(apk, splits, reinstall=True,
+                             allow_cached_props=True, permissions=())
+    else:
+      device.Install(apk, reinstall=True, permissions=())
+    install_timer.Stop(log=False)
+
+  # Push .so and .dex files to the device (if they have changed).
+  def do_push_files():
+    if native_libs:
+      push_native_timer.Start()
+      with build_utils.TempDir() as temp_dir:
+        device_lib_dir = posixpath.join(device_incremental_dir, 'lib')
+        for path in native_libs:
+          os.symlink(path, os.path.join(temp_dir, os.path.basename(path)))
+        device.PushChangedFiles([(temp_dir, device_lib_dir)],
+                                delete_device_stale=True)
+      push_native_timer.Stop(log=False)
+
+    if dex_files:
+      push_dex_timer.Start()
+      # Put all .dex files to be pushed into a temporary directory so that we
+      # can use delete_device_stale=True.
+      with build_utils.TempDir() as temp_dir:
+        device_dex_dir = posixpath.join(device_incremental_dir, 'dex')
+        # Ensure no two files have the same name.
+        transformed_names = _TransformDexPaths(dex_files)
+        for src_path, dest_name in zip(dex_files, transformed_names):
+          os.symlink(src_path, os.path.join(temp_dir, dest_name))
+        device.PushChangedFiles([(temp_dir, device_dex_dir)],
+                                delete_device_stale=True)
+      push_dex_timer.Stop(log=False)
+
+  def check_selinux():
+    # Marshmallow has no filesystem access whatsoever. It might be possible to
+    # get things working on Lollipop, but attempts so far have failed.
+    # http://crbug.com/558818
+    has_selinux = device.build_version_sdk >= version_codes.LOLLIPOP
+    if has_selinux and apk.HasIsolatedProcesses():
+      raise Exception('Cannot use incremental installs on Android L+ without '
+                      'first disabling isoloated processes.\n'
+                      'To do so, use GN arg:\n'
+                      '    disable_incremental_isolated_processes=true')
+
+  cache_path = '%s/files-cache.json' % device_incremental_dir
+  def restore_cache():
+    if not enable_device_cache:
+      logging.info('Ignoring device cache')
+      return
+    # Delete the cached file so that any exceptions cause the next attempt
+    # to re-compute md5s.
+    cmd = 'P=%s;cat $P 2>/dev/null && rm $P' % cache_path
+    lines = device.RunShellCommand(cmd, check_return=False, large_output=True)
+    if lines:
+      device.LoadCacheData(lines[0])
+    else:
+      logging.info('Device cache not found: %s', cache_path)
+
+  def save_cache():
+    cache_data = device.DumpCacheData()
+    device.WriteFile(cache_path, cache_data)
+
+  # Create 2 lock files:
+  # * install.lock tells the app to pause on start-up (until we release it).
+  # * firstrun.lock is used by the app to pause all secondary processes until
+  #   the primary process finishes loading the .dex / .so files.
+  def create_lock_files():
+    # Creates or zeros out lock files.
+    cmd = ('D="%s";'
+           'mkdir -p $D &&'
+           'echo -n >$D/install.lock 2>$D/firstrun.lock')
+    device.RunShellCommand(cmd % device_incremental_dir, check_return=True)
+
+  # The firstrun.lock is released by the app itself.
+  def release_installer_lock():
+    device.RunShellCommand('echo > %s/install.lock' % device_incremental_dir,
+                           check_return=True)
+
+  # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't
+  # been designed for multi-threading. Enabling only because this is a
+  # developer-only tool.
+  setup_timer = _Execute(
+      use_concurrency, create_lock_files, restore_cache, check_selinux)
+
+  _Execute(use_concurrency, do_install, do_push_files)
+
+  finalize_timer = _Execute(use_concurrency, release_installer_lock, save_cache)
+
+  logging.info(
+      'Took %s seconds (setup=%s, install=%s, libs=%s, dex=%s, finalize=%s)',
+      main_timer.GetDelta(), setup_timer.GetDelta(), install_timer.GetDelta(),
+      push_native_timer.GetDelta(), push_dex_timer.GetDelta(),
+      finalize_timer.GetDelta())
+  if show_proguard_warning:
+    logging.warning('Target had proguard enabled, but incremental install uses '
+                    'non-proguarded .dex files. Performance characteristics '
+                    'may differ.')
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('apk_path',
+                      help='The path to the APK to install.')
+  parser.add_argument('--split',
+                      action='append',
+                      dest='splits',
+                      help='A glob matching the apk splits. '
+                           'Can be specified multiple times.')
+  parser.add_argument('--native_lib',
+                      dest='native_libs',
+                      help='Path to native library (repeatable)',
+                      action='append',
+                      default=[])
+  parser.add_argument('--dex-file',
+                      dest='dex_files',
+                      help='Path to dex files (repeatable)',
+                      action='append',
+                      default=[])
+  parser.add_argument('-d', '--device', dest='device',
+                      help='Target device for apk to install on.')
+  parser.add_argument('--uninstall',
+                      action='store_true',
+                      default=False,
+                      help='Remove the app and all side-loaded files.')
+  parser.add_argument('--output-directory',
+                      help='Path to the root build directory.')
+  parser.add_argument('--no-threading',
+                      action='store_false',
+                      default=True,
+                      dest='threading',
+                      help='Do not install and push concurrently')
+  parser.add_argument('--no-cache',
+                      action='store_false',
+                      default=True,
+                      dest='cache',
+                      help='Do not use cached information about what files are '
+                           'currently on the target device.')
+  parser.add_argument('--show-proguard-warning',
+                      action='store_true',
+                      default=False,
+                      help='Print a warning about proguard being disabled')
+  parser.add_argument('-v',
+                      '--verbose',
+                      dest='verbose_count',
+                      default=0,
+                      action='count',
+                      help='Verbose level (multiple times for more)')
+
+  args = parser.parse_args()
+
+  run_tests_helper.SetLogLevel(args.verbose_count)
+  constants.SetBuildType('Debug')
+  if args.output_directory:
+    constants.SetOutputDirectory(args.output_directory)
+
+  if args.device:
+    # Retries are annoying when commands fail for legitimate reasons. Might want
+    # to enable them if this is ever used on bots though.
+    device = device_utils.DeviceUtils(
+        args.device, default_retries=0, enable_device_files_cache=True)
+  else:
+    devices = device_utils.DeviceUtils.HealthyDevices(
+        default_retries=0, enable_device_files_cache=True)
+    if not devices:
+      raise device_errors.NoDevicesError()
+    elif len(devices) == 1:
+      device = devices[0]
+    else:
+      all_devices = device_utils.DeviceUtils.parallel(devices)
+      msg = ('More than one device available.\n'
+             'Use --device=SERIAL to select a device.\n'
+             'Available devices:\n')
+      descriptions = all_devices.pMap(lambda d: d.build_description).pGet(None)
+      for d, desc in zip(devices, descriptions):
+        msg += '  %s (%s)\n' % (d, desc)
+      raise Exception(msg)
+
+  apk = apk_helper.ToHelper(args.apk_path)
+  if args.uninstall:
+    Uninstall(device, apk.GetPackageName())
+  else:
+    Install(device, apk, split_globs=args.splits, native_libs=args.native_libs,
+            dex_files=args.dex_files, enable_device_cache=args.cache,
+            use_concurrency=args.threading,
+            show_proguard_warning=args.show_proguard_warning)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java
new file mode 100644
index 0000000..67c60e5
--- /dev/null
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java
@@ -0,0 +1,235 @@
+// Copyright 2015 The Chromium 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.incrementalinstall;
+
+import android.app.Application;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An Application that replaces itself with another Application (as defined in
+ * an AndroidManifext.xml meta-data tag). It loads the other application only
+ * after side-loading its .so and .dex files from /data/local/tmp.
+ *
+ * This class is highly dependent on the private implementation details of
+ * Android's ActivityThread.java. However, it has been tested to work with
+ * JellyBean through Marshmallow.
+ */
+public final class BootstrapApplication extends Application {
+    private static final String TAG = "cr.incrementalinstall";
+    private static final String MANAGED_DIR_PREFIX = "/data/local/tmp/incremental-app-";
+    private static final String REAL_APP_META_DATA_NAME = "incremental-install-real-app";
+    private static final String REAL_INSTRUMENTATION_META_DATA_NAME =
+            "incremental-install-real-instrumentation";
+
+    private ClassLoaderPatcher mClassLoaderPatcher;
+    private Application mRealApplication;
+    private Instrumentation mRealInstrumentation;
+    private Object mStashedProviderList;
+    private Object mActivityThread;
+
+    @Override
+    protected void attachBaseContext(Context context) {
+        super.attachBaseContext(context);
+        File incrementalRootDir = new File(MANAGED_DIR_PREFIX + context.getPackageName());
+        File libDir = new File(incrementalRootDir, "lib");
+        File dexDir = new File(incrementalRootDir, "dex");
+        File installLockFile = new File(incrementalRootDir, "install.lock");
+        File firstRunLockFile = new File(incrementalRootDir, "firstrun.lock");
+
+        try {
+            mActivityThread = Reflect.invokeMethod(Class.forName("android.app.ActivityThread"),
+                    "currentActivityThread");
+            mClassLoaderPatcher = new ClassLoaderPatcher(context);
+
+            boolean isFirstRun = LockFile.installerLockExists(firstRunLockFile);
+            if (isFirstRun) {
+                if (mClassLoaderPatcher.mIsPrimaryProcess) {
+                    // Wait for incremental_install.py to finish.
+                    LockFile.waitForInstallerLock(installLockFile, 30 * 1000);
+                } else {
+                    // Wait for the browser process to create the optimized dex files
+                    // and copy the library files.
+                    LockFile.waitForInstallerLock(firstRunLockFile, 60 * 1000);
+                }
+            }
+
+            mClassLoaderPatcher.importNativeLibs(libDir);
+            mClassLoaderPatcher.loadDexFiles(dexDir);
+
+            if (isFirstRun && mClassLoaderPatcher.mIsPrimaryProcess) {
+                LockFile.clearInstallerLock(firstRunLockFile);
+            }
+
+            // mInstrumentationAppDir is one of a set of fields that is initialized only when
+            // instrumentation is active.
+            if (Reflect.getField(mActivityThread, "mInstrumentationAppDir") != null) {
+                String realInstrumentationName =
+                        getClassNameFromMetadata(REAL_INSTRUMENTATION_META_DATA_NAME);
+                initInstrumentation(realInstrumentationName);
+            } else {
+                Log.i(TAG, "No instrumentation active.");
+            }
+
+            // Even when instrumentation is not enabled, ActivityThread uses a default
+            // Instrumentation instance internally. We hook it here in order to hook into the
+            // call to Instrumentation.onCreate().
+            Reflect.setField(mActivityThread, "mInstrumentation",
+                    new BootstrapInstrumentation(this));
+
+            // attachBaseContext() is called from ActivityThread#handleBindApplication() and
+            // Application#mApplication is changed right after we return. Thus, we cannot swap
+            // the Application instances until onCreate() is called.
+            String realApplicationName = getClassNameFromMetadata(REAL_APP_META_DATA_NAME);
+            Log.i(TAG, "Instantiating " + realApplicationName);
+            mRealApplication =
+                    (Application) Reflect.newInstance(Class.forName(realApplicationName));
+            Reflect.invokeMethod(mRealApplication, "attachBaseContext", context);
+
+            // Between attachBaseContext() and onCreate(), ActivityThread tries to instantiate
+            // all ContentProviders. The ContentProviders break without the correct Application
+            // class being installed, so temporarily pretend there are no providers, and then
+            // instantiate them explicitly within onCreate().
+            disableContentProviders();
+            Log.i(TAG, "Waiting for Instrumentation.onCreate");
+        } catch (Exception e) {
+            throw new RuntimeException("Incremental install failed.", e);
+        }
+    }
+
+    /**
+     * Returns the fully-qualified class name for the given key, stored in a
+     * &lt;meta&gt; witin the manifest.
+     */
+    private String getClassNameFromMetadata(String key) throws NameNotFoundException {
+        ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(),
+                PackageManager.GET_META_DATA);
+        String value = appInfo.metaData.getString(key);
+        if (!value.contains(".")) {
+            value = getPackageName() + "." + value;
+        }
+        return value;
+    }
+
+    /**
+     * Instantiates and initializes mRealInstrumentation (the real Instrumentation class).
+     */
+    private void initInstrumentation(String realInstrumentationName)
+            throws ReflectiveOperationException {
+        Log.i(TAG, "Instantiating instrumentation " + realInstrumentationName);
+        mRealInstrumentation = (Instrumentation) Reflect.newInstance(
+                Class.forName(realInstrumentationName));
+        Instrumentation oldInstrumentation =
+                (Instrumentation) Reflect.getField(mActivityThread, "mInstrumentation");
+
+        // Initialize the fields that are set by Instrumentation.init().
+        String[] initFields = {"mThread", "mMessageQueue", "mInstrContext", "mAppContext",
+                "mWatcher", "mUiAutomationConnection"};
+        for (String fieldName : initFields) {
+            Reflect.setField(mRealInstrumentation, fieldName,
+                    Reflect.getField(oldInstrumentation, fieldName));
+        }
+        // But make sure the correct ComponentName is used.
+        ComponentName newName = new ComponentName(
+                oldInstrumentation.getComponentName().getPackageName(), realInstrumentationName);
+        Reflect.setField(mRealInstrumentation, "mComponent", newName);
+    }
+
+    /**
+     * Called by BootstrapInstrumentation from Instrumentation.onCreate().
+     * This happens regardless of whether or not instrumentation is enabled.
+     */
+    void onInstrumentationCreate(Bundle arguments) {
+        Log.i(TAG, "Instrumentation.onCreate() called. Swapping references.");
+        try {
+            swapApplicationReferences();
+            enableContentProviders();
+            if (mRealInstrumentation != null) {
+                Reflect.setField(mActivityThread, "mInstrumentation", mRealInstrumentation);
+                mRealInstrumentation.onCreate(arguments);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Incremental install failed.", e);
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        try {
+            Log.i(TAG, "Application.onCreate() called.");
+            mRealApplication.onCreate();
+        } catch (Exception e) {
+            throw new RuntimeException("Incremental install failed.", e);
+        }
+    }
+
+    /**
+     * Nulls out ActivityThread.mBoundApplication.providers.
+     */
+    private void disableContentProviders() throws ReflectiveOperationException {
+        Object data = Reflect.getField(mActivityThread, "mBoundApplication");
+        mStashedProviderList = Reflect.getField(data, "providers");
+        Reflect.setField(data, "providers", null);
+    }
+
+    /**
+     * Restores the value of ActivityThread.mBoundApplication.providers, and invokes
+     * ActivityThread#installContentProviders().
+     */
+    private void enableContentProviders() throws ReflectiveOperationException {
+        Object data = Reflect.getField(mActivityThread, "mBoundApplication");
+        Reflect.setField(data, "providers", mStashedProviderList);
+        if (mStashedProviderList != null && mClassLoaderPatcher.mIsPrimaryProcess) {
+            Log.i(TAG, "Instantiating content providers");
+            Reflect.invokeMethod(mActivityThread, "installContentProviders", mRealApplication,
+                    mStashedProviderList);
+        }
+        mStashedProviderList = null;
+    }
+
+    /**
+     * Changes all fields within framework classes that have stored an reference to this
+     * BootstrapApplication to instead store references to mRealApplication.
+     * @throws NoSuchFieldException
+     */
+    @SuppressWarnings("unchecked")
+    private void swapApplicationReferences() throws ReflectiveOperationException {
+        if (Reflect.getField(mActivityThread, "mInitialApplication") == this) {
+            Reflect.setField(mActivityThread, "mInitialApplication", mRealApplication);
+        }
+
+        List<Application> allApplications =
+                (List<Application>) Reflect.getField(mActivityThread, "mAllApplications");
+        for (int i = 0; i < allApplications.size(); i++) {
+            if (allApplications.get(i) == this) {
+                allApplications.set(i, mRealApplication);
+            }
+        }
+
+        for (String fieldName : new String[] { "mPackages", "mResourcePackages" }) {
+            Map<String, WeakReference<?>> packageMap =
+                    (Map<String, WeakReference<?>>) Reflect.getField(mActivityThread, fieldName);
+            for (Map.Entry<String, WeakReference<?>> entry : packageMap.entrySet()) {
+                Object loadedApk = entry.getValue().get();
+                if (loadedApk != null && Reflect.getField(loadedApk, "mApplication") == this) {
+                    Reflect.setField(loadedApk, "mApplication", mRealApplication);
+                    Reflect.setField(mRealApplication, "mLoadedApk", loadedApk);
+                }
+            }
+        }
+    }
+}
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapInstrumentation.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapInstrumentation.java
new file mode 100644
index 0000000..f197406
--- /dev/null
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapInstrumentation.java
@@ -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.
+
+package org.chromium.incrementalinstall;
+
+import android.app.Instrumentation;
+import android.os.Bundle;
+
+/**
+ * Notifies BootstrapApplication of the call to Instrumentation.onCreate().
+ */
+public final class BootstrapInstrumentation extends Instrumentation {
+    private final BootstrapApplication mApp;
+
+    BootstrapInstrumentation(BootstrapApplication app) {
+        mApp = app;
+    }
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+        mApp.onInstrumentationCreate(arguments);
+    }
+}
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java
new file mode 100644
index 0000000..c1682e8
--- /dev/null
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java
@@ -0,0 +1,228 @@
+// Copyright 2015 The Chromium 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.incrementalinstall;
+
+import android.content.Context;
+import android.os.Build;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Provides the ability to add native libraries and .dex files to an existing class loader.
+ * Tested with Jellybean MR2 - Marshmellow.
+ */
+final class ClassLoaderPatcher {
+    private static final String TAG = "cr.incrementalinstall";
+    private final File mAppFilesSubDir;
+    private final ClassLoader mClassLoader;
+    private final Object mLibcoreOs;
+    private final int mProcessUid;
+    final boolean mIsPrimaryProcess;
+
+    ClassLoaderPatcher(Context context) throws ReflectiveOperationException {
+        mAppFilesSubDir =
+                new File(context.getApplicationInfo().dataDir, "incremental-install-files");
+        mClassLoader = context.getClassLoader();
+        mLibcoreOs = Reflect.getField(Class.forName("libcore.io.Libcore"), "os");
+        mProcessUid = (Integer) Reflect.invokeMethod(mLibcoreOs, "getuid");
+        mIsPrimaryProcess = context.getApplicationInfo().uid == mProcessUid;
+        Log.i(TAG, "uid=" + mProcessUid + " (isPrimary=" + mIsPrimaryProcess + ")");
+    }
+
+    /**
+     * Loads all dex files within |dexDir| into the app's ClassLoader.
+     */
+    void loadDexFiles(File dexDir) throws ReflectiveOperationException, FileNotFoundException {
+        Log.i(TAG, "Installing dex files from: " + dexDir);
+        File[] dexFilesArr = dexDir.listFiles();
+        if (dexFilesArr == null) {
+            throw new FileNotFoundException("Dex dir does not exist: " + dexDir);
+        }
+        // The optimized dex files will be owned by this process' user.
+        // Store them within the app's data dir rather than on /data/local/tmp
+        // so that they are still deleted (by the OS) when we uninstall
+        // (even on a non-rooted device).
+        File incrementalDexesDir = new File(mAppFilesSubDir, "optimized-dexes");
+        File isolatedDexesDir = new File(mAppFilesSubDir, "isolated-dexes");
+        File optimizedDir;
+
+        if (mIsPrimaryProcess) {
+            ensureAppFilesSubDirExists();
+            // Allows isolated processes to access the same files.
+            incrementalDexesDir.mkdir();
+            incrementalDexesDir.setReadable(true, false);
+            incrementalDexesDir.setExecutable(true, false);
+            // Create a directory for isolated processes to create directories in.
+            isolatedDexesDir.mkdir();
+            isolatedDexesDir.setWritable(true, false);
+            isolatedDexesDir.setExecutable(true, false);
+
+            optimizedDir = incrementalDexesDir;
+        } else {
+            // There is a UID check of the directory in dalvik.system.DexFile():
+            // https://android.googlesource.com/platform/libcore/+/45e0260/dalvik/src/main/java/dalvik/system/DexFile.java#101
+            // Rather than have each isolated process run DexOpt though, we use
+            // symlinks within the directory to point at the browser process'
+            // optimized dex files.
+            optimizedDir = new File(isolatedDexesDir, "isolated-" + mProcessUid);
+            optimizedDir.mkdir();
+            // Always wipe it out and re-create for simplicity.
+            Log.i(TAG, "Creating dex file symlinks for isolated process");
+            for (File f : optimizedDir.listFiles()) {
+                f.delete();
+            }
+            for (File f : incrementalDexesDir.listFiles()) {
+                String to = "../../" + incrementalDexesDir.getName() + "/" + f.getName();
+                File from = new File(optimizedDir, f.getName());
+                createSymlink(to, from);
+            }
+        }
+
+        Log.i(TAG, "Code cache dir: " + optimizedDir);
+        // TODO(agrieve): Might need to record classpath ordering if we ever have duplicate
+        //     class names (since then order will matter here).
+        Log.i(TAG, "Loading " + dexFilesArr.length + " dex files");
+
+        Object dexPathList = Reflect.getField(mClassLoader, "pathList");
+        Object[] dexElements = (Object[]) Reflect.getField(dexPathList, "dexElements");
+        Object[] additionalElements = makeDexElements(dexFilesArr, optimizedDir);
+        Reflect.setField(
+                dexPathList, "dexElements", Reflect.concatArrays(dexElements, additionalElements));
+    }
+
+    /**
+     * Sets up all libraries within |libDir| to be loadable by System.loadLibrary().
+     */
+    void importNativeLibs(File libDir) throws ReflectiveOperationException, IOException {
+        Log.i(TAG, "Importing native libraries from: " + libDir);
+        // The library copying is not necessary on older devices, but we do it anyways to
+        // simplify things (it's fast compared to dexing).
+        // https://code.google.com/p/android/issues/detail?id=79480
+        File localLibsDir = new File(mAppFilesSubDir, "lib");
+        File copyLibsLockFile = new File(mAppFilesSubDir, "libcopy.lock");
+        if (mIsPrimaryProcess) {
+            // Primary process: Copies native libraries into the app's data directory.
+            ensureAppFilesSubDirExists();
+            LockFile lockFile = LockFile.acquireRuntimeLock(copyLibsLockFile);
+            if (lockFile == null) {
+                LockFile.waitForRuntimeLock(copyLibsLockFile, 10 * 1000);
+            } else {
+                try {
+                    localLibsDir.mkdir();
+                    localLibsDir.setReadable(true, false);
+                    localLibsDir.setExecutable(true, false);
+                    copyChangedFiles(libDir, localLibsDir);
+                } finally {
+                    lockFile.release();
+                }
+            }
+        } else {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                // TODO: Work around this issue by using APK splits to install each dex / lib.
+                throw new RuntimeException("Incremental install does not work on Android M+ "
+                        + "with isolated processes. Use the gn arg:\n"
+                        + "    disable_incremental_isolated_processes=true\n"
+                        + "and try again.");
+            }
+            // Other processes: Waits for primary process to finish copying.
+            LockFile.waitForRuntimeLock(copyLibsLockFile, 10 * 1000);
+        }
+        addNativeLibrarySearchPath(localLibsDir);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void addNativeLibrarySearchPath(File nativeLibDir) throws ReflectiveOperationException {
+        Object dexPathList = Reflect.getField(mClassLoader, "pathList");
+        Object currentDirs = Reflect.getField(dexPathList, "nativeLibraryDirectories");
+        File[] newDirs = new File[] { nativeLibDir };
+        // Switched from an array to an ArrayList in Lollipop.
+        if (currentDirs instanceof List) {
+            List<File> dirsAsList = (List<File>) currentDirs;
+            dirsAsList.add(nativeLibDir);
+        } else {
+            File[] dirsAsArray = (File[]) currentDirs;
+            Reflect.setField(dexPathList, "nativeLibraryDirectories",
+                    Reflect.concatArrays(dirsAsArray, newDirs));
+        }
+
+        Object[] nativeLibraryPathElements;
+        try {
+            nativeLibraryPathElements =
+                    (Object[]) Reflect.getField(dexPathList, "nativeLibraryPathElements");
+        } catch (NoSuchFieldException e) {
+            // This field doesn't exist pre-M.
+            return;
+        }
+        Object[] additionalElements = makeNativePathElements(newDirs);
+        Reflect.setField(
+                dexPathList, "nativeLibraryPathElements",
+                Reflect.concatArrays(nativeLibraryPathElements, additionalElements));
+    }
+
+    private static void copyChangedFiles(File srcDir, File dstDir) throws IOException {
+        // No need to delete stale libs since libraries are loaded explicitly.
+        for (File f : srcDir.listFiles()) {
+            // Note: Tried using hardlinks, but resulted in EACCES exceptions.
+            File dest = new File(dstDir, f.getName());
+            copyIfModified(f, dest);
+        }
+    }
+
+    private static void copyIfModified(File src, File dest) throws IOException {
+        long lastModified = src.lastModified();
+        if (!dest.exists() || dest.lastModified() != lastModified) {
+            Log.i(TAG, "Copying " + src + " -> " + dest);
+            FileInputStream istream = new FileInputStream(src);
+            FileOutputStream ostream = new FileOutputStream(dest);
+            ostream.getChannel().transferFrom(istream.getChannel(), 0, istream.getChannel().size());
+            istream.close();
+            ostream.close();
+            dest.setReadable(true, false);
+            dest.setExecutable(true,  false);
+            dest.setLastModified(lastModified);
+        } else {
+            Log.i(TAG, "Up-to-date: " + dest);
+        }
+    }
+
+    private void ensureAppFilesSubDirExists() {
+        mAppFilesSubDir.mkdir();
+        mAppFilesSubDir.setExecutable(true, false);
+    }
+
+    private void createSymlink(String to, File from) throws ReflectiveOperationException {
+        Reflect.invokeMethod(mLibcoreOs, "symlink", to, from.getAbsolutePath());
+    }
+
+    private static Object[] makeNativePathElements(File[] paths)
+            throws ReflectiveOperationException {
+        Class<?> entryClazz = Class.forName("dalvik.system.DexPathList$Element");
+        Object[] entries = new Object[paths.length];
+        for (int i = 0; i < paths.length; ++i) {
+            entries[i] = Reflect.newInstance(entryClazz, paths[i], true, null, null);
+        }
+        return entries;
+    }
+
+    private static Object[] makeDexElements(File[] files, File optimizedDirectory)
+            throws ReflectiveOperationException {
+        Class<?> entryClazz = Class.forName("dalvik.system.DexPathList$Element");
+        Class<?> clazz = Class.forName("dalvik.system.DexPathList");
+        Object[] entries = new Object[files.length];
+        File emptyDir = new File("");
+        for (int i = 0; i < files.length; ++i) {
+            File file = files[i];
+            Object dexFile = Reflect.invokeMethod(clazz, "loadDexFile", file, optimizedDirectory);
+            entries[i] = Reflect.newInstance(entryClazz, emptyDir, false, file, dexFile);
+        }
+        return entries;
+    }
+}
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/LockFile.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/LockFile.java
new file mode 100644
index 0000000..6e48f3b
--- /dev/null
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/LockFile.java
@@ -0,0 +1,129 @@
+// Copyright 2015 The Chromium 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.incrementalinstall;
+
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileLock;
+import java.util.concurrent.Callable;
+
+/**
+ * Helpers for dealing with .lock files used during install / first run.
+ */
+final class LockFile {
+    private static final String TAG = "cr.incrementalinstall";
+
+    private final File mFile;
+    private final FileOutputStream mOutputStream;
+    private final FileLock mFileLock;
+
+    private LockFile(File file, FileOutputStream outputStream, FileLock fileLock) {
+        mFile = file;
+        mOutputStream = outputStream;
+        mFileLock = fileLock;
+    }
+
+    /**
+     * Clears the lock file by writing to it (making it non-zero in length);
+     */
+    static void clearInstallerLock(File lockFile) throws IOException {
+        Log.i(TAG, "Clearing " + lockFile);
+        // On Android M+, we can't delete files in /data/local/tmp, so we write to it instead.
+        FileOutputStream os = new FileOutputStream(lockFile);
+        os.write(1);
+        os.close();
+    }
+
+    /**
+     * Waits for the given file to be non-zero in length.
+     */
+    static void waitForInstallerLock(final File file, long timeoutMs) {
+        pollingWait(new Callable<Boolean>() {
+            @Override public Boolean call() {
+                return !installerLockExists(file);
+            }
+        }, file, timeoutMs);
+    }
+
+    /**
+     * Waits for the given file to be non-zero in length.
+     */
+    private static void pollingWait(Callable<Boolean> func, File file, long timeoutMs) {
+        long pollIntervalMs = 200;
+        for (int i = 0; i < timeoutMs / pollIntervalMs; i++) {
+            try {
+                if (func.call()) {
+                    if (i > 0) {
+                        Log.i(TAG, "Finished waiting on lock file: " + file);
+                    }
+                    return;
+                } else if (i == 0) {
+                    Log.i(TAG, "Waiting on lock file: " + file);
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+            try {
+                Thread.sleep(pollIntervalMs);
+            } catch (InterruptedException e) {
+                // Should never happen.
+            }
+        }
+        throw new RuntimeException("Timed out waiting for lock file: " + file);
+    }
+
+    /**
+     * Returns whether the given lock file is missing or is in the locked state.
+     */
+    static boolean installerLockExists(File file) {
+        return !file.exists() || file.length() == 0;
+    }
+
+    /**
+     * Attempts to acquire a lock for the given file.
+     * @return Returns the FileLock if it was acquired, or null otherwise.
+     */
+    static LockFile acquireRuntimeLock(File file) {
+        try {
+            FileOutputStream outputStream = new FileOutputStream(file);
+            FileLock lock = outputStream.getChannel().tryLock();
+            if (lock != null) {
+                Log.i(TAG, "Created lock file: " + file);
+                return new LockFile(file, outputStream, lock);
+            }
+            outputStream.close();
+        } catch (IOException e) {
+            // Do nothing. We didn't get the lock.
+            Log.w(TAG, "Exception trying to acquire lock " + file, e);
+        }
+        return null;
+    }
+
+    /**
+     * Waits for the given file to not exist.
+     */
+    static void waitForRuntimeLock(final File file, long timeoutMs) {
+        pollingWait(new Callable<Boolean>() {
+            @Override public Boolean call() {
+                return !file.exists();
+            }
+        }, file, timeoutMs);
+    }
+
+    /**
+     * Releases and deletes the lock file.
+     */
+    void release() throws IOException {
+        Log.i(TAG, "Deleting lock file: " + mFile);
+        mFileLock.release();
+        mOutputStream.close();
+        if (!mFile.delete()) {
+            throw new IOException("Failed to delete lock file: " + mFile);
+        }
+    }
+}
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/Reflect.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/Reflect.java
new file mode 100644
index 0000000..7790690
--- /dev/null
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/Reflect.java
@@ -0,0 +1,142 @@
+// Copyright 2015 The Chromium 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.incrementalinstall;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+/**
+ * Reflection helper methods.
+ */
+final class Reflect {
+    /**
+     * Sets the value of an object's field (even if it's not visible).
+     *
+     * @param instance The object containing the field to set.
+     * @param name The name of the field to set.
+     * @param value The new value for the field.
+     */
+    static void setField(Object instance, String name, Object value)
+            throws ReflectiveOperationException {
+        Field field = findField(instance, name);
+        field.setAccessible(true);
+        field.set(instance, value);
+    }
+
+    /**
+     * Retrieves the value of an object's field (even if it's not visible).
+     *
+     * @param instance The object containing the field to set.
+     * @param name The name of the field to set.
+     * @return The field's value. Primitive values are returned as their boxed
+     *         type.
+     */
+    static Object getField(Object instance, String name) throws ReflectiveOperationException {
+        Field field = findField(instance, name);
+        field.setAccessible(true);
+        return field.get(instance);
+    }
+
+    /**
+     * Concatenates two arrays into a new array. The arrays must be of the same
+     * type.
+     */
+    static Object[] concatArrays(Object[] left, Object[] right) {
+        Object[] result = (Object[]) Array.newInstance(
+                left.getClass().getComponentType(), left.length + right.length);
+        System.arraycopy(left, 0, result, 0, left.length);
+        System.arraycopy(right, 0, result, left.length, right.length);
+        return result;
+    }
+
+    /**
+     * Invokes a method with zero or more parameters. For static methods, use the Class as the
+     * instance.
+     */
+    static Object invokeMethod(Object instance, String name, Object... params)
+            throws ReflectiveOperationException {
+        boolean isStatic = instance instanceof Class;
+        Class<?> clazz = isStatic ? (Class<?>) instance :  instance.getClass();
+        Method method = findMethod(clazz, name, params);
+        method.setAccessible(true);
+        return method.invoke(instance, params);
+    }
+
+    /**
+     * Calls a constructor with zero or more parameters.
+     */
+    static Object newInstance(Class<?> clazz, Object... params)
+            throws ReflectiveOperationException {
+        Constructor<?> constructor = findConstructor(clazz, params);
+        constructor.setAccessible(true);
+        return constructor.newInstance(params);
+    }
+
+    private static Field findField(Object instance, String name) throws NoSuchFieldException {
+        boolean isStatic = instance instanceof Class;
+        Class<?> clazz = isStatic ? (Class<?>) instance :  instance.getClass();
+        for (; clazz != null; clazz = clazz.getSuperclass()) {
+            try {
+                return clazz.getDeclaredField(name);
+            } catch (NoSuchFieldException e) {
+                // Need to look in the super class.
+            }
+        }
+        throw new NoSuchFieldException("Field " + name + " not found in " + instance.getClass());
+    }
+
+    private static Method findMethod(Class<?> clazz, String name, Object... params)
+            throws NoSuchMethodException {
+        for (; clazz != null; clazz = clazz.getSuperclass()) {
+            for (Method method : clazz.getDeclaredMethods()) {
+                if (method.getName().equals(name)
+                        && areParametersCompatible(method.getParameterTypes(), params)) {
+                    return method;
+                }
+            }
+        }
+        throw new NoSuchMethodException("Method " + name + " with parameters "
+                + Arrays.asList(params) + " not found in " + clazz);
+    }
+
+    private static Constructor<?> findConstructor(Class<?> clazz, Object... params)
+            throws NoSuchMethodException {
+        for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
+            if (areParametersCompatible(constructor.getParameterTypes(), params)) {
+                return constructor;
+            }
+        }
+        throw new NoSuchMethodException("Constructor with parameters " + Arrays.asList(params)
+                + " not found in " + clazz);
+    }
+
+    private static boolean areParametersCompatible(Class<?>[] paramTypes, Object... params) {
+        if (params.length != paramTypes.length) {
+            return false;
+        }
+        for (int i = 0; i < params.length; i++) {
+            if (!isAssignableFrom(paramTypes[i], params[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean isAssignableFrom(Class<?> left, Object right) {
+        if (right == null) {
+            return !left.isPrimitive();
+        }
+        Class<?> rightClazz = right.getClass();
+        if (left.isPrimitive()) {
+            // TODO(agrieve): Fill in the rest as needed.
+            return left == boolean.class && rightClazz == Boolean.class
+                   || left == int.class && rightClazz == Integer.class;
+        }
+        return left.isAssignableFrom(rightClazz);
+    }
+}
diff --git a/build/android/install_emulator_deps.py b/build/android/install_emulator_deps.py
index 82d1c75..354c59d 100755
--- a/build/android/install_emulator_deps.py
+++ b/build/android/install_emulator_deps.py
@@ -14,34 +14,19 @@
 import optparse
 import os
 import re
-import shutil
 import sys
 
-from pylib import cmd_helper
+from devil.utils import cmd_helper
+from devil.utils import run_tests_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
+# Default Time out for downloading SDK component
+DOWNLOAD_SYSTEM_IMAGE_TIMEOUT = 30
+DOWNLOAD_SDK_PLATFORM_TIMEOUT = 60
 
 def CheckSDK():
   """Check if SDK is already installed.
@@ -49,7 +34,7 @@
   Returns:
     True if the emulator SDK directory (src/android_emulator_sdk/) exists.
   """
-  return os.path.exists(constants.EMULATOR_SDK_ROOT)
+  return os.path.exists(constants.ANDROID_SDK_ROOT)
 
 
 def CheckSDKPlatform(api_level=DEFAULT_ANDROID_API_LEVEL):
@@ -63,8 +48,7 @@
   Returns:
     True if the platform is already installed.
   """
-  android_binary = os.path.join(constants.EMULATOR_SDK_ROOT,
-                                'sdk', 'tools', 'android')
+  android_binary = os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'android')
   pattern = re.compile('id: [0-9]+ or "android-%d"' % api_level)
   try:
     exit_code, stdout = cmd_helper.GetCmdStatusAndOutput(
@@ -87,13 +71,12 @@
     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.
+    True if x86 image has been previously downloaded.
   """
   api_target = 'android-%d' % api_level
-  return os.path.exists(os.path.join(constants.EMULATOR_SDK_ROOT,
-                                     'sdk', 'system-images',
-                                     api_target, 'x86'))
+  return os.path.exists(os.path.join(constants.ANDROID_SDK_ROOT,
+                                     'system-images', api_target, 'default',
+                                     'x86'))
 
 
 def CheckKVM():
@@ -122,25 +105,6 @@
     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'])
@@ -160,6 +124,48 @@
                      'AMD SVM).')
 
 
+def UpdateSDK(api_level, package_name, package_pattern, timeout):
+  """This function update SDK with a filter index.
+
+  Args:
+    api_level: the Android API level to download for.
+    package_name: logging name of package that is being updated.
+    package_pattern: the pattern to match the filter index from.
+    timeout: the amount of time wait for update command.
+  """
+  android_binary = os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'android')
+
+  list_sdk_repo_command = [android_binary, 'list', 'sdk', '--all']
+
+  exit_code, stdout = cmd_helper.GetCmdStatusAndOutput(list_sdk_repo_command)
+
+  if exit_code != 0:
+    raise Exception('\'android list sdk --all\' command return %d' % exit_code)
+
+  for line in stdout.split('\n'):
+    match = package_pattern.match(line)
+    if match:
+      index = match.group(1)
+      logging.info('package %s corresponds to %s with api level %d',
+                   index, package_name, api_level)
+      update_command = [android_binary, 'update', 'sdk', '--no-ui', '--all',
+                         '--filter', index]
+      update_command_str = ' '.join(update_command)
+      logging.info('running update command: %s', update_command_str)
+      update_process = pexpect.spawn(update_command_str)
+
+      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.', timeout=timeout) == 0:
+        logging.info('Successfully installed %s for API level %d',
+                      package_name, 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 GetX86Image(api_level=DEFAULT_ANDROID_API_LEVEL):
   """Download x86 system image from Intel's website.
 
@@ -167,24 +173,12 @@
     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)
 
+  x86_package_pattern = re.compile(
+    r'\s*([0-9]+)- Intel x86 Atom System Image, Android API %d.*' % api_level)
+
+  UpdateSDK(api_level, 'x86 system image', x86_package_pattern,
+            DOWNLOAD_SYSTEM_IMAGE_TIMEOUT)
 
 def GetSDKPlatform(api_level=DEFAULT_ANDROID_API_LEVEL):
   """Update the SDK to include the platform specified.
@@ -192,76 +186,53 @@
   Args:
     api_level: the Android API level to download
   """
-  android_binary = os.path.join(constants.EMULATOR_SDK_ROOT,
-                                'sdk', 'tools', 'android')
-  pattern = re.compile(
+  logging.info('Download SDK Platform directory into sdk directory.')
+
+  platform_package_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)
+
+  UpdateSDK(api_level, 'SDK Platform', platform_package_pattern,
+            DOWNLOAD_SDK_PLATFORM_TIMEOUT)
 
 
 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')
+  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='verbosity',
+                        default=1,
+                        action='count',
+                        help='Verbose level (multiple times for more)')
   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)
+  run_tests_helper.SetLogLevel(verbose_count=options.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.')
+    logging.info('android_emulator_sdk/ exists')
   else:
-    GetSDK()
+    logging.critical('ERROR: Emulator SDK not installed in %s'
+                     , constants.ANDROID_SDK_ROOT)
+    return 1
 
   # 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.' %
+    logging.info('SDK platform android-%d already present, skipping.',
                  options.api_level)
   else:
-    logging.info('SDK platform android-%d not present, installing.' %
+    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.' %
+    logging.info('x86 image for android-%d already present, skipping.',
                  options.api_level)
   else:
     GetX86Image(options.api_level)
diff --git a/build/android/java_cpp_template.gypi b/build/android/java_cpp_template.gypi
index 3296659..f4ea0a9 100644
--- a/build/android/java_cpp_template.gypi
+++ b/build/android/java_cpp_template.gypi
@@ -34,6 +34,7 @@
 {
   # Location where all generated Java sources will be placed.
   'variables': {
+    'additional_gcc_preprocess_options': [],
     'include_path%': '<(DEPTH)',
     'output_dir': '<(SHARED_INTERMEDIATE_DIR)/templates/<(_target_name)/<(package_name)',
   },
@@ -74,6 +75,7 @@
         '--include-path=<(include_path)',
         '--output=<(output_path)',
         '--template=<(RULE_INPUT_PATH)',
+        '<@(additional_gcc_preprocess_options)',
       ],
       'message': 'Generating Java from cpp template <(RULE_INPUT_PATH)',
     }
diff --git a/build/android/java_google_api_keys.gyp b/build/android/java_google_api_keys.gyp
new file mode 100644
index 0000000..df046b6
--- /dev/null
+++ b/build/android/java_google_api_keys.gyp
@@ -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.
+
+# This file provides an action to generate Java source files from the Google
+# API keys using a Python script.
+
+{
+  'targets': [
+    {
+      'target_name': 'google_api_keys_java',
+      'type': 'none',
+      'variables': {
+        # Location where all generated Java sources will be placed.
+        'output_dir': '<(SHARED_INTERMEDIATE_DIR)/java_google_api_keys',
+        'generator_path': '<(DEPTH)/build/android/gyp/java_google_api_keys.py',
+        'output_file': '<(output_dir)/GoogleAPIKeys.java',
+      },
+      '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)/',
+          ],
+        },
+      },
+      'actions': [
+        {
+          'action_name': 'generate_java_google_api_keys',
+          'inputs': [
+            '<(generator_path)',
+          ],
+          'outputs': [
+            '<(output_file)',
+          ],
+          'action': [
+            'python', '<(generator_path)', '--out', '<(output_file)'
+          ],
+          'message': 'Generating Java from Google API Keys header',
+        },
+      ],
+    },
+  ],
+}
diff --git a/build/android/jinja_template.gypi b/build/android/jinja_template.gypi
index 9c49360..7fcddd6 100644
--- a/build/android/jinja_template.gypi
+++ b/build/android/jinja_template.gypi
@@ -8,12 +8,12 @@
 # To process a single template file, create a gyp target with the following
 # form:
 #  {
-#    'target_name': 'chrome_shell_manifest',
+#    'target_name': 'chrome_public_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'],
+#      'jinja_inputs': ['android/java/AndroidManifest.xml'],
+#      'jinja_output': '<(SHARED_INTERMEDIATE_DIR)/chrome_public_manifest/AndroidManifest.xml',
+#      'jinja_variables': ['app_name=ChromePublic'],
 #    },
 #    'includes': [ '../build/android/jinja_template.gypi' ],
 #  },
@@ -24,13 +24,13 @@
 #    'target_name': 'chrome_template_resources',
 #    'type': 'none',
 #    'variables': {
-#       'jinja_inputs_base_dir': 'android/shell/java/res_template',
+#       'jinja_inputs_base_dir': 'android/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'],
+#       'jinja_variables': ['app_name=ChromePublic'],
 #     },
 #     'includes': [ '../build/android/jinja_template.gypi' ],
 #   },
diff --git a/build/android/lighttpd_server.py b/build/android/lighttpd_server.py
index a5195ac..5c2dde8 100755
--- a/build/android/lighttpd_server.py
+++ b/build/android/lighttpd_server.py
@@ -140,7 +140,7 @@
       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)
+        server_msg += self.process.match.group(0) # pylint: disable=no-member
       elif ix == 1:  # EOF -- server has quit so giveup.
         client_error = client_error or 'Server exited'
         break
diff --git a/build/android/lint/suppress.py b/build/android/lint/suppress.py
index 52d7579..1c254b7 100755
--- a/build/android/lint/suppress.py
+++ b/build/android/lint/suppress.py
@@ -6,6 +6,8 @@
 
 """Add all generated lint_result.xml files to suppressions.xml"""
 
+# pylint: disable=no-member
+
 
 import collections
 import optparse
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index b16de84..61d062d 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -41,6 +41,10 @@
   <issue id="HandlerLeak">
     <ignore path="remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java"/>
   </issue>
+  <issue id="IconMissingDensityFolder">
+    <!-- see crbug.com/542435 -->
+    <ignore path="android_webview/apk/java/res" />
+  </issue>
   <issue id="IconDensities">
     <!-- crbug.com/457918 is tracking missing assets -->
     <ignore path="components/web_contents_delegate_android/android/java/res/drawable-xxhdpi"/>
@@ -51,11 +55,18 @@
     <ignore path="chrome/android/java/res/drawable-xxxhdpi"/>
     <ignore path="ui/android/java/res/drawable-xxhdpi"/>
     <ignore path="ui/android/java/res/drawable-xxxhdpi"/>
+    <ignore regexp=".*: data_reduction_illustration.png, google_icon_sprite.png, reader_mode_bar_background.9.png, tabs_moved_htc.png, tabs_moved_nexus.png, tabs_moved_samsung.png$"/>
   </issue>
-  <!-- It is OK for content_shell_apk and chrome_shell_apk to have missing assets. -->
+  <issue id="IconDipSize">
+    <ignore regexp=".*google_icon_sprite.png.*"/>
+  </issue>
   <issue id="IconLocation">
+    <!-- It is OK for content_shell_apk to have missing assets. -->
     <ignore path="content/shell/android/java/res/"/>
-    <ignore path="chrome/android/shell/res/"/>
+    <!-- Suppression for chrome/test/chromedriver/test/webview_shell/java/res/drawable/icon.png -->
+    <ignore path="res/drawable/icon.png"/>
+    <!-- TODO(lambroslambrou) remove this once crbug.com/502030 is fixed. -->
+    <ignore path="remoting/android/java/res"/>
   </issue>
   <issue id="InconsistentLayout" severity="ignore"/>
   <issue id="InflateParams" severity="ignore"/>
@@ -72,6 +83,7 @@
     <ignore path="org/chromium/base/SysUtils.class"/>
     <ignore path="org/chromium/chrome/browser/TtsPlatformImpl.class"/>
     <ignore path="org/chromium/chrome/browser/TtsPlatformImpl$*.class"/>
+    <ignore path="chrome/android/java/res/values-v17/styles.xml"/>
   </issue>
   <issue id="OldTargetApi">
     <ignore path="AndroidManifest.xml"/>
@@ -87,13 +99,19 @@
   </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" />
+    <!-- Used by chrome/android/java/AndroidManifest.xml -->
+    <ignore path="chrome/android/java/res/drawable/window_background.xml" />
+    <ignore path="chrome/android/java/res/xml/bookmark_thumbnail_widget_info.xml" />
+    <ignore path="chrome/android/java/res/xml/file_paths.xml" />
+
+    <ignore path="content/shell/android/shell_apk/res/layout/content_shell_activity.xml" />
+    <ignore path="content/shell/android/shell_apk/res/values/strings.xml" />
   </issue>
   <issue id="SignatureOrSystemPermissions" severity="ignore"/>
   <issue id="UnusedAttribute" severity="ignore"/>
   <issue id="ViewConstructor" severity="ignore"/>
   <issue id="WrongCall" severity="ignore"/>
+  <issue id="UselessParent">
+    <ignore path="chrome/android/java/res/layout/data_reduction_promo_screen.xml" />
+  </issue>
 </lint>
diff --git a/build/android/lint_action.gypi b/build/android/lint_action.gypi
index e042130..f38e5c9 100644
--- a/build/android/lint_action.gypi
+++ b/build/android/lint_action.gypi
@@ -18,17 +18,18 @@
     ],
     'android_manifest_path%': '<(DEPTH)/build/android/AndroidManifest.xml',
     'resource_dir%': '<(DEPTH)/build/android/ant/empty/res',
+    'suppressions_file%': '<(DEPTH)/build/android/lint/suppressions.xml',
   },
   'inputs': [
     '<(DEPTH)/build/android/gyp/util/build_utils.py',
     '<(DEPTH)/build/android/gyp/lint.py',
-    '<(DEPTH)/build/android/lint/suppressions.xml',
+    '<(suppressions_file)',
     '<(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',
+    '--config-path=<(suppressions_file)',
     '--processed-config-path=<(config_path)',
     '--manifest-path=<(android_manifest_path)',
     '--result-path=<(result_path)',
@@ -36,6 +37,7 @@
     '--product-dir=<(PRODUCT_DIR)',
     '--src-dirs=>(src_dirs)',
     '--jar-path=<(lint_jar_path)',
+    '--can-fail-build',
     '--stamp=<(stamp_path)',
     '<(is_enabled)',
   ],
diff --git a/build/android/locale_pak_resources.gypi b/build/android/locale_pak_resources.gypi
new file mode 100644
index 0000000..020b831
--- /dev/null
+++ b/build/android/locale_pak_resources.gypi
@@ -0,0 +1,54 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Creates a resources.zip with locale.pak files placed into appropriate
+# resource configs (e.g. en-GB.pak -> res/raw-en/en_gb.pak). Also generates
+# a locale_paks TypedArray so that resource files can be enumerated at runtime.
+#
+# If this target is included in the deps of an android resources/library/apk,
+# the resources will be included with that target.
+#
+# Variables:
+#   locale_pak_files - List of .pak files to process.
+#     Names must be of the form "en.pak" or "en-US.pak".
+#   resource_zip_path - the path of generated zip file, optional, normally, you
+#     don't need to set this variable.
+#
+# Example
+#  {
+#    'target_name': 'my_locale_resources',
+#    'type': 'none',
+#    'variables': {
+#      'locale_paks_files': ['path1/fr.pak'],
+#    },
+#    'includes': [ '../build/android/locale_pak_resources.gypi' ],
+#  },
+#
+{
+  'variables': {
+    'resources_zip_path%': '<(PRODUCT_DIR)/res.java/<(_target_name).zip',
+  },
+  'all_dependent_settings': {
+    'variables': {
+      'additional_locale_input_paths': ['<(resources_zip_path)'],
+      'dependencies_locale_zip_paths': ['<(resources_zip_path)'],
+    },
+  },
+  'actions': [{
+    'action_name': '<(_target_name)_locale_pak_resources',
+    'inputs': [
+      '<(DEPTH)/build/android/gyp/util/build_utils.py',
+      '<(DEPTH)/build/android/gyp/locale_pak_resources.py',
+      '<@(locale_pak_files)',
+    ],
+    'outputs': [
+      '<(resources_zip_path)',
+    ],
+    'action': [
+      'python', '<(DEPTH)/build/android/gyp/locale_pak_resources.py',
+      '--locale-paks', '<(locale_pak_files)',
+      '--resources-zip', '<(resources_zip_path)',
+    ],
+  }],
+}
diff --git a/build/android/main_dex_action.gypi b/build/android/main_dex_action.gypi
new file mode 100644
index 0000000..4076418
--- /dev/null
+++ b/build/android/main_dex_action.gypi
@@ -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.
+
+# This file is meant to be included into an action to provide a rule that
+# generates a list of classes that must be kept in the main dex file.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'action_name': 'some name for the action'
+#    'actions': [
+#      'variables': {
+#        'jar_paths': ['path to jar', ...],
+#        'output_path': 'output path',
+#      },
+#      'includes': [ 'relative/path/to/main_dex_action.gypi' ],
+#    ],
+#  },
+#
+
+{
+  'message': 'Generating main dex classes list for <(jar_path)',
+  'variables': {
+    'jar_paths%': [],
+    'output_path%': '',
+    'main_dex_list_script': '<(DEPTH)/build/android/gyp/main_dex_list.py',
+    'main_dex_rules_path': '<(DEPTH)/build/android/main_dex_classes.flags',
+  },
+  'inputs': [
+    '<@(jar_paths)',
+    '<(main_dex_list_script)',
+    '<(main_dex_rules_path)',
+    '<(multidex_configuration_path)',
+  ],
+  'outputs': [
+    '<(output_path)',
+  ],
+  'action': [
+    'python', '<(main_dex_list_script)',
+    '--main-dex-list-path', '<(output_path)',
+    '--android-sdk-tools', '<(android_sdk_tools)',
+    '--main-dex-rules-path', '<(main_dex_rules_path)',
+    '--multidex-configuration-path', '<(multidex_configuration_path)',
+    '<@(jar_paths)',
+  ]
+}
diff --git a/build/android/main_dex_classes.flags b/build/android/main_dex_classes.flags
new file mode 100644
index 0000000..a8d969a
--- /dev/null
+++ b/build/android/main_dex_classes.flags
@@ -0,0 +1,7 @@
+-keep @**.MainDex class * {
+  *;
+}
+
+-keepclasseswithmembers class * {
+  public static ** asInterface(android.os.IBinder);
+}
diff --git a/build/android/method_count.py b/build/android/method_count.py
new file mode 100755
index 0000000..f2feb6f
--- /dev/null
+++ b/build/android/method_count.py
@@ -0,0 +1,75 @@
+#! /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 argparse
+import os
+import re
+import shutil
+import sys
+import tempfile
+import zipfile
+
+from devil.android.sdk import dexdump
+from pylib import constants
+
+sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib',
+                             'common'))
+import perf_tests_results_helper # pylint: disable=import-error
+
+
+_METHOD_IDS_SIZE_RE = re.compile(r'^method_ids_size +: +(\d+)$')
+
+def ExtractIfZip(dexfile, tmpdir):
+  if not dexfile.endswith('.zip'):
+    return [dexfile]
+
+  with zipfile.ZipFile(dexfile, 'r') as z:
+    z.extractall(tmpdir)
+
+  return [os.path.join(tmpdir, f) for f in os.listdir(tmpdir)]
+
+def SingleMethodCount(dexfile):
+  for line in dexdump.DexDump(dexfile, file_summary=True):
+    m = _METHOD_IDS_SIZE_RE.match(line)
+    if m:
+      return m.group(1)
+  raise Exception('"method_ids_size" not found in dex dump of %s' % dexfile)
+
+def MethodCount(dexfile):
+  tmpdir = tempfile.mkdtemp(suffix='_dex_extract')
+  multidex_file_list = ExtractIfZip(dexfile, tmpdir)
+  try:
+    return sum(int(SingleMethodCount(d)) for d in multidex_file_list)
+  finally:
+    shutil.rmtree(tmpdir)
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      '--apk-name', help='Name of the APK to which the dexfile corresponds.')
+  parser.add_argument('dexfile')
+
+  args = parser.parse_args()
+
+  if not args.apk_name:
+    dirname, basename = os.path.split(args.dexfile)
+    while basename:
+      if 'apk' in basename:
+        args.apk_name = basename
+        break
+      dirname, basename = os.path.split(dirname)
+    else:
+      parser.error(
+          'Unable to determine apk name from %s, '
+          'and --apk-name was not provided.' % args.dexfile)
+
+  method_count = MethodCount(args.dexfile)
+  perf_tests_results_helper.PrintPerfResult(
+      '%s_methods' % args.apk_name, 'total', [method_count], 'methods')
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
+
diff --git a/build/android/native_app_dependencies.gypi b/build/android/native_app_dependencies.gypi
index 6032274..f74e7ae 100644
--- a/build/android/native_app_dependencies.gypi
+++ b/build/android/native_app_dependencies.gypi
@@ -29,7 +29,7 @@
     'include_main_binary%': 1,
   },
   'conditions': [
-      ['component == "shared_library"', {
+      ['android_must_copy_system_libraries == 1', {
         'dependencies': [
           '<(DEPTH)/build/android/setup.gyp:copy_system_libraries',
         ],
diff --git a/build/android/pack_arm_relocations.gypi b/build/android/pack_relocations.gypi
similarity index 69%
rename from build/android/pack_arm_relocations.gypi
rename to build/android/pack_relocations.gypi
index 5df1d7e..61b4e2c 100644
--- a/build/android/pack_arm_relocations.gypi
+++ b/build/android/pack_relocations.gypi
@@ -3,11 +3,11 @@
 # 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.
+# packs relocations in Release builds of native libraries.
 #
 # To use this, create a gyp target with the following form:
 #  {
-#    'action_name': 'pack_arm_relocations',
+#    'action_name': 'pack_relocations',
 #    'actions': [
 #      'variables': {
 #        'enable_packing': 'pack relocations if 1, plain file copy if 0'
@@ -17,7 +17,7 @@
 #        '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' ],
+#      'includes': [ '../../build/android/pack_relocations.gypi' ],
 #    ],
 #  },
 #
@@ -25,17 +25,10 @@
 {
   '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',
+    '<(DEPTH)/build/android/gyp/pack_relocations.py',
     '<(ordered_libraries_file)',
     '>@(input_paths)',
   ],
@@ -44,21 +37,19 @@
   ],
   'conditions': [
     ['enable_packing == 1', {
-      'message': 'Packing ARM relative relocations for <(_target_name)',
+      'message': 'Packing relocations for <(_target_name)',
       'dependencies': [
-        '<(DEPTH)/tools/relocation_packer/relocation_packer.gyp:relocation_packer#host',
+        '<(DEPTH)/third_party/android_platform/relocation_packer.gyp:android_relocation_packer#host',
       ],
       'inputs': [
-        '<(PRODUCT_DIR)/relocation_packer',
+        '<(PRODUCT_DIR)/android_relocation_packer',
       ],
       'action': [
-        'python', '<(DEPTH)/build/android/gyp/pack_arm_relocations.py',
+        'python', '<(DEPTH)/build/android/gyp/pack_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)',
+        '--android-pack-relocations=<(PRODUCT_DIR)/android_relocation_packer',
         '--stripped-libraries-dir=<(stripped_libraries_dir)',
         '--packed-libraries-dir=<(packed_libraries_dir)',
         '--libraries=@FileArg(<(ordered_libraries_file):libraries)',
@@ -67,7 +58,7 @@
     }, {
       'message': 'Copying libraries (no relocation packing) for <(_target_name)',
       'action': [
-        'python', '<(DEPTH)/build/android/gyp/pack_arm_relocations.py',
+        'python', '<(DEPTH)/build/android/gyp/pack_relocations.py',
         '--configuration-name=<(CONFIGURATION_NAME)',
         '--enable-packing=0',
         '--stripped-libraries-dir=<(stripped_libraries_dir)',
@@ -76,7 +67,7 @@
         '--stamp=<(stamp)',
       ],
     }],
-    ['component == "shared_library"', {
+    ['android_must_copy_system_libraries == 1', {
       # 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.
diff --git a/build/android/package_resources_action.gypi b/build/android/package_resources_action.gypi
new file mode 100644
index 0000000..c3529b3
--- /dev/null
+++ b/build/android/package_resources_action.gypi
@@ -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 is a helper to java_apk.gypi. It should be used to create an
+# action that runs ApkBuilder via ANT.
+#
+# Required variables:
+#  apk_name - File name (minus path & extension) of the output apk.
+#  android_manifest_path - Path to AndroidManifest.xml.
+#  app_manifest_version_name - set the apps 'human readable' version number.
+#  app_manifest_version_code - set the apps version number.
+# Optional variables:
+#  asset_location - The directory where assets are located (if any).
+#  create_density_splits - Whether to create density-based apk splits. Splits
+#    are supported only for minSdkVersion >= 21.
+#  language_splits - List of languages to create apk splits for.
+#  resource_zips - List of paths to resource zip files.
+#  shared_resources - Make a resource package that can be loaded by a different
+#    application at runtime to access the package's resources.
+#  app_as_shared_library - Make a resource package that can be loaded as shared
+#    library.
+#  extensions_to_not_compress - E.g.: 'pak,dat,bin'
+#  extra_inputs - List of extra action inputs.
+{
+  'variables': {
+    'asset_location%': '',
+    'create_density_splits%': 0,
+    'resource_zips%': [],
+    'shared_resources%': 0,
+    'app_as_shared_library%': 0,
+    'extensions_to_not_compress%': '',
+    'extra_inputs%': [],
+    'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
+    'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
+  },
+  'action_name': 'package_resources_<(apk_name)',
+  'message': 'packaging resources for <(apk_name)',
+  '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)',
+    '<@(extra_inputs)',
+  ],
+  'outputs': [
+    '<(resource_packaged_apk_path)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/package_resources.py',
+    '--android-sdk', '<(android_sdk)',
+    '--aapt-path', '<(android_aapt_path)',
+    '--configuration-name', '<(CONFIGURATION_NAME)',
+    '--android-manifest', '<(android_manifest_path)',
+    '--version-code', '<(app_manifest_version_code)',
+    '--version-name', '<(app_manifest_version_name)',
+    '--no-compress', '<(extensions_to_not_compress)',
+    '--apk-path', '<(resource_packaged_apk_path)',
+  ],
+  'conditions': [
+    ['shared_resources == 1', {
+      'action': [
+        '--shared-resources',
+      ],
+    }],
+    ['app_as_shared_library == 1', {
+      'action': [
+        '--app-as-shared-lib',
+      ],
+    }],
+    ['asset_location != ""', {
+      'action': [
+        '--asset-dir', '<(asset_location)',
+      ],
+    }],
+    ['create_density_splits == 1', {
+      'action': [
+        '--create-density-splits',
+      ],
+      'outputs': [
+        '<(resource_packaged_apk_path)_hdpi',
+        '<(resource_packaged_apk_path)_xhdpi',
+        '<(resource_packaged_apk_path)_xxhdpi',
+        '<(resource_packaged_apk_path)_xxxhdpi',
+        '<(resource_packaged_apk_path)_tvdpi',
+      ],
+    }],
+    ['language_splits != []', {
+      'action': [
+        '--language-splits=<(language_splits)',
+      ],
+      'outputs': [
+        "<!@(python <(DEPTH)/build/apply_locales.py '<(resource_packaged_apk_path)_ZZLOCALE' <(language_splits))",
+      ],
+    }],
+    ['resource_zips != []', {
+      'action': [
+        '--resource-zips', '>(resource_zips)',
+      ],
+      'inputs': [
+        '>@(resource_zips)',
+      ],
+    }],
+  ],
+}
diff --git a/build/android/play_services/LICENSE.sha1 b/build/android/play_services/LICENSE.sha1
new file mode 100644
index 0000000..8e606a7
--- /dev/null
+++ b/build/android/play_services/LICENSE.sha1
@@ -0,0 +1 @@
+11cc73d4b7fa82560fbf5bbc1095dbac30308e7c
\ No newline at end of file
diff --git a/build/android/pylib/uiautomator/__init__.py b/build/android/play_services/__init__.py
similarity index 61%
copy from build/android/pylib/uiautomator/__init__.py
copy to build/android/play_services/__init__.py
index cda7672..50b23df 100644
--- a/build/android/pylib/uiautomator/__init__.py
+++ b/build/android/play_services/__init__.py
@@ -1,4 +1,3 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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/play_services/config.json b/build/android/play_services/config.json
new file mode 100644
index 0000000..f4f9c6e
--- /dev/null
+++ b/build/android/play_services/config.json
@@ -0,0 +1,3 @@
+{
+  "version_number": 8298000
+}
diff --git a/build/android/play_services/google_play_services_library.zip.sha1 b/build/android/play_services/google_play_services_library.zip.sha1
new file mode 100644
index 0000000..113d55a
--- /dev/null
+++ b/build/android/play_services/google_play_services_library.zip.sha1
@@ -0,0 +1 @@
+07308d03b3a83f2985c52e5cfe2764220e19e223
\ No newline at end of file
diff --git a/build/android/play_services/update.py b/build/android/play_services/update.py
new file mode 100755
index 0000000..c6c8dcc
--- /dev/null
+++ b/build/android/play_services/update.py
@@ -0,0 +1,513 @@
+#!/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 help uploading and downloading the Google Play services library to
+and from a Google Cloud storage.
+'''
+
+import argparse
+import logging
+import os
+import re
+import shutil
+import sys
+import tempfile
+import zipfile
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from devil.utils import cmd_helper
+from play_services import utils
+from pylib import constants
+from pylib.utils import logging_utils
+
+sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT, 'build'))
+import find_depot_tools  # pylint: disable=import-error,unused-import
+import breakpad
+import download_from_google_storage
+import upload_to_google_storage
+
+
+# Directory where the SHA1 files for the zip and the license are stored
+# It should be managed by git to provided information about new versions.
+SHA1_DIRECTORY = os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android',
+                              'play_services')
+
+# Default bucket used for storing the files.
+GMS_CLOUD_STORAGE = 'chromium-android-tools/play-services'
+
+# Path to the default configuration file. It exposes the currently installed
+# version of the library in a human readable way.
+CONFIG_DEFAULT_PATH = os.path.join(constants.DIR_SOURCE_ROOT, 'build',
+                                   'android', 'play_services', 'config.json')
+
+LICENSE_FILE_NAME = 'LICENSE'
+ZIP_FILE_NAME = 'google_play_services_library.zip'
+GMS_PACKAGE_ID = 'extra-google-google_play_services'  # used by sdk manager
+
+LICENSE_PATTERN = re.compile(r'^Pkg\.License=(?P<text>.*)$', re.MULTILINE)
+
+
+def main(raw_args):
+  parser = argparse.ArgumentParser(
+      description=__doc__ + 'Please see the subcommand help for more details.',
+      formatter_class=utils.DefaultsRawHelpFormatter)
+  subparsers = parser.add_subparsers(title='commands')
+
+  # Download arguments
+  parser_download = subparsers.add_parser(
+      'download',
+      help='download the library from the cloud storage',
+      description=Download.__doc__,
+      formatter_class=utils.DefaultsRawHelpFormatter)
+  parser_download.set_defaults(func=Download)
+  AddBasicArguments(parser_download)
+  AddBucketArguments(parser_download)
+
+  # SDK Update arguments
+  parser_sdk = subparsers.add_parser(
+      'sdk',
+      help='get the latest Google Play services SDK using Android SDK Manager',
+      description=UpdateSdk.__doc__,
+      formatter_class=utils.DefaultsRawHelpFormatter)
+  parser_sdk.set_defaults(func=UpdateSdk)
+  AddBasicArguments(parser_sdk)
+
+  # Upload arguments
+  parser_upload = subparsers.add_parser(
+      'upload',
+      help='upload the library to the cloud storage',
+      description=Upload.__doc__,
+      formatter_class=utils.DefaultsRawHelpFormatter)
+
+  parser_upload.add_argument('--skip-git',
+                             action='store_true',
+                             help="don't commit the changes at the end")
+  parser_upload.set_defaults(func=Upload)
+  AddBasicArguments(parser_upload)
+  AddBucketArguments(parser_upload)
+
+  args = parser.parse_args(raw_args)
+  if args.verbose:
+    logging.basicConfig(level=logging.DEBUG)
+  logging_utils.ColorStreamHandler.MakeDefault(not _IsBotEnvironment())
+  return args.func(args)
+
+
+def AddBasicArguments(parser):
+  '''
+  Defines the common arguments on subparser rather than the main one. This
+  allows to put arguments after the command: `foo.py upload --debug --force`
+  instead of `foo.py --debug upload --force`
+  '''
+
+  parser.add_argument('--sdk-root',
+                      help='base path to the Android SDK tools root',
+                      default=constants.ANDROID_SDK_ROOT)
+
+  parser.add_argument('-v', '--verbose',
+                      action='store_true',
+                      help='print debug information')
+
+
+def AddBucketArguments(parser):
+  parser.add_argument('--bucket',
+                      help='name of the bucket where the files are stored',
+                      default=GMS_CLOUD_STORAGE)
+
+  parser.add_argument('--config',
+                      help='JSON Configuration file',
+                      default=CONFIG_DEFAULT_PATH)
+
+  parser.add_argument('--dry-run',
+                      action='store_true',
+                      help=('run the script in dry run mode. Files will be '
+                            'copied to a local directory instead of the '
+                            'cloud storage. The bucket name will be as path '
+                            'to that directory relative to the repository '
+                            'root.'))
+
+  parser.add_argument('-f', '--force',
+                      action='store_true',
+                      help='run even if the library is already up to date')
+
+
+def Download(args):
+  '''
+  Downloads the Google Play services library from a Google Cloud Storage bucket
+  and installs it to
+  //third_party/android_tools/sdk/extras/google/google_play_services.
+
+  A license check will be made, and the user might have to accept the license
+  if that has not been done before.
+  '''
+
+  if not os.path.isdir(args.sdk_root):
+    logging.debug('Did not find the Android SDK root directory at "%s".',
+                  args.sdk_root)
+    if not args.force:
+      logging.info('Skipping, not on an android checkout.')
+      return 0
+
+  paths = PlayServicesPaths(args.sdk_root)
+
+  if os.path.isdir(paths.package) and not os.access(paths.package, os.W_OK):
+    logging.error('Failed updating the Google Play Services library. '
+                  'The location is not writable. Please remove the '
+                  'directory (%s) and try again.', paths.package)
+    return -2
+
+  new_lib_zip_sha1 = os.path.join(SHA1_DIRECTORY, ZIP_FILE_NAME + '.sha1')
+
+  logging.debug('Comparing zip hashes: %s and %s', new_lib_zip_sha1,
+                paths.lib_zip_sha1)
+  if utils.FileEquals(new_lib_zip_sha1, paths.lib_zip_sha1) and not args.force:
+    logging.info('Skipping, the Google Play services library is up to date.')
+    return 0
+
+  config = utils.ConfigParser(args.config)
+  bucket_path = _VerifyBucketPathFormat(args.bucket,
+                                        config.version_number,
+                                        args.dry_run)
+
+  tmp_root = tempfile.mkdtemp()
+  try:
+    # setup the destination directory
+    if not os.path.isdir(paths.package):
+      os.makedirs(paths.package)
+
+    # download license file from bucket/{version_number}/license.sha1
+    new_license = os.path.join(tmp_root, LICENSE_FILE_NAME)
+
+    license_sha1 = os.path.join(SHA1_DIRECTORY, LICENSE_FILE_NAME + '.sha1')
+    _DownloadFromBucket(bucket_path, license_sha1, new_license,
+                        args.verbose, args.dry_run)
+
+    if (not _IsBotEnvironment() and
+        not _CheckLicenseAgreement(new_license, paths.license,
+                                   config.version_number)):
+        logging.warning('Your version of the Google Play services library is '
+                        'not up to date. You might run into issues building '
+                        'or running the app. Please run `%s download` to '
+                        'retry downloading it.', __file__)
+        return 0
+
+    new_lib_zip = os.path.join(tmp_root, ZIP_FILE_NAME)
+    _DownloadFromBucket(bucket_path, new_lib_zip_sha1, new_lib_zip,
+                        args.verbose, args.dry_run)
+
+    try:
+      # We remove the current version of the Google Play services SDK.
+      if os.path.exists(paths.package):
+        shutil.rmtree(paths.package)
+      os.makedirs(paths.package)
+
+      logging.debug('Extracting the library to %s', paths.lib)
+      with zipfile.ZipFile(new_lib_zip, "r") as new_lib_zip_file:
+        new_lib_zip_file.extractall(paths.lib)
+
+      logging.debug('Copying %s to %s', new_license, paths.license)
+      shutil.copy(new_license, paths.license)
+
+      logging.debug('Copying %s to %s', new_lib_zip_sha1, paths.lib_zip_sha1)
+      shutil.copy(new_lib_zip_sha1, paths.lib_zip_sha1)
+
+      logging.info('Update complete.')
+
+    except Exception as e:  # pylint: disable=broad-except
+      logging.error('Failed updating the Google Play Services library. '
+                    'An error occurred while installing the new version in '
+                    'the SDK directory: %s ', e)
+      return -3
+  finally:
+    shutil.rmtree(tmp_root)
+
+  return 0
+
+
+def UpdateSdk(args):
+  '''
+  Uses the Android SDK Manager to download the latest Google Play services SDK
+  locally. Its usual installation path is
+  //third_party/android_tools/sdk/extras/google/google_play_services
+  '''
+
+  # This should function should not run on bots and could fail for many user
+  # and setup related reasons. Also, exceptions here are not caught, so we
+  # disable breakpad to avoid spamming the logs.
+  breakpad.IS_ENABLED = False
+
+  sdk_manager = os.path.join(args.sdk_root, 'tools', 'android')
+  cmd = [sdk_manager, 'update', 'sdk', '--no-ui', '--filter', GMS_PACKAGE_ID]
+  cmd_helper.Call(cmd)
+  # If no update is needed, it still returns successfully so we just do nothing
+
+  return 0
+
+
+def Upload(args):
+  '''
+  Uploads the library from the local Google Play services SDK to a Google Cloud
+  storage bucket.
+
+  By default, a local commit will be made at the end of the operation.
+  '''
+
+  # This should function should not run on bots and could fail for many user
+  # and setup related reasons. Also, exceptions here are not caught, so we
+  # disable breakpad to avoid spamming the logs.
+  breakpad.IS_ENABLED = False
+
+  paths = PlayServicesPaths(args.sdk_root)
+
+  if not args.skip_git and utils.IsRepoDirty(constants.DIR_SOURCE_ROOT):
+    logging.error('The repo is dirty. Please commit or stash your changes.')
+    return -1
+
+  config = utils.ConfigParser(args.config)
+
+  new_version_number = utils.GetVersionNumberFromLibraryResources(
+      paths.version_xml)
+  logging.debug('comparing versions: new=%d, old=%s',
+                new_version_number, config.version_number)
+  if new_version_number <= config.version_number and not args.force:
+    logging.info('The checked in version of the library is already the latest '
+                 'one. No update is needed. Please rerun with --force to skip '
+                 'this check.')
+    return 0
+
+  tmp_root = tempfile.mkdtemp()
+  try:
+    new_lib_zip = os.path.join(tmp_root, ZIP_FILE_NAME)
+    new_license = os.path.join(tmp_root, LICENSE_FILE_NAME)
+
+    # need to strip '.zip' from the file name here
+    shutil.make_archive(new_lib_zip[:-4], 'zip', paths.lib)
+    _ExtractLicenseFile(new_license, paths.source_prop)
+
+    bucket_path = _VerifyBucketPathFormat(args.bucket, new_version_number,
+                                          args.dry_run)
+    files_to_upload = [new_lib_zip, new_license]
+    logging.debug('Uploading %s to %s', files_to_upload, bucket_path)
+    _UploadToBucket(bucket_path, files_to_upload, args.dry_run)
+
+    new_lib_zip_sha1 = os.path.join(SHA1_DIRECTORY,
+                                    ZIP_FILE_NAME + '.sha1')
+    new_license_sha1 = os.path.join(SHA1_DIRECTORY,
+                                    LICENSE_FILE_NAME + '.sha1')
+    shutil.copy(new_lib_zip + '.sha1', new_lib_zip_sha1)
+    shutil.copy(new_license + '.sha1', new_license_sha1)
+  finally:
+    shutil.rmtree(tmp_root)
+
+  config.UpdateVersionNumber(new_version_number)
+
+  if not args.skip_git:
+    commit_message = ('Update the Google Play services dependency to %s\n'
+                      '\n') % new_version_number
+    utils.MakeLocalCommit(constants.DIR_SOURCE_ROOT,
+                          [new_lib_zip_sha1, new_license_sha1, config.path],
+                          commit_message)
+
+  return 0
+
+
+def _DownloadFromBucket(bucket_path, sha1_file, destination, verbose,
+                        is_dry_run):
+  '''Downloads the file designated by the provided sha1 from a cloud bucket.'''
+
+  download_from_google_storage.download_from_google_storage(
+      input_filename=sha1_file,
+      base_url=bucket_path,
+      gsutil=_InitGsutil(is_dry_run),
+      num_threads=1,
+      directory=None,
+      recursive=False,
+      force=False,
+      output=destination,
+      ignore_errors=False,
+      sha1_file=sha1_file,
+      verbose=verbose,
+      auto_platform=True,
+      extract=False)
+
+
+def _UploadToBucket(bucket_path, files_to_upload, is_dry_run):
+  '''Uploads the files designated by the provided paths to a cloud bucket. '''
+
+  upload_to_google_storage.upload_to_google_storage(
+      input_filenames=files_to_upload,
+      base_url=bucket_path,
+      gsutil=_InitGsutil(is_dry_run),
+      force=False,
+      use_md5=False,
+      num_threads=1,
+      skip_hashing=False,
+      gzip=None)
+
+
+def _InitGsutil(is_dry_run):
+  '''Initialize the Gsutil object as regular or dummy version for dry runs. '''
+
+  if is_dry_run:
+    return DummyGsutil()
+  else:
+    return download_from_google_storage.Gsutil(
+        download_from_google_storage.GSUTIL_DEFAULT_PATH)
+
+
+def _ExtractLicenseFile(license_path, prop_file_path):
+  with open(prop_file_path, 'r') as prop_file:
+    prop_file_content = prop_file.read()
+
+  match = LICENSE_PATTERN.search(prop_file_content)
+  if not match:
+    raise AttributeError('The license was not found in ' +
+                         os.path.abspath(prop_file_path))
+
+  with open(license_path, 'w') as license_file:
+    license_file.write(match.group('text'))
+
+
+def _CheckLicenseAgreement(expected_license_path, actual_license_path,
+                           version_number):
+  '''
+  Checks that the new license is the one already accepted by the user. If it
+  isn't, it prompts the user to accept it. Returns whether the expected license
+  has been accepted.
+  '''
+
+  if utils.FileEquals(expected_license_path, actual_license_path):
+    return True
+
+  with open(expected_license_path) as license_file:
+    # Uses plain print rather than logging to make sure this is not formatted
+    # by the logger.
+    print ('Updating the Google Play services SDK to '
+           'version %d.' % version_number)
+
+    # The output is buffered when running as part of gclient hooks. We split
+    # the text here and flush is explicitly to avoid having part of it dropped
+    # out.
+    # Note: text contains *escaped* new lines, so we split by '\\n', not '\n'.
+    for license_part in license_file.read().split('\\n'):
+      print license_part
+      sys.stdout.flush()
+
+  # Need to put the prompt on a separate line otherwise the gclient hook buffer
+  # only prints it after we received an input.
+  print 'Do you accept the license? [y/n]: '
+  sys.stdout.flush()
+  return raw_input('> ') in ('Y', 'y')
+
+
+def _IsBotEnvironment():
+  return bool(os.environ.get('CHROME_HEADLESS'))
+
+
+def _VerifyBucketPathFormat(bucket_name, version_number, is_dry_run):
+  '''
+  Formats and checks the download/upload path depending on whether we are
+  running in dry run mode or not. Returns a supposedly safe path to use with
+  Gsutil.
+  '''
+
+  if is_dry_run:
+    bucket_path = os.path.abspath(os.path.join(bucket_name,
+                                               str(version_number)))
+    if not os.path.isdir(bucket_path):
+      os.makedirs(bucket_path)
+  else:
+    if bucket_name.startswith('gs://'):
+      # We enforce the syntax without gs:// for consistency with the standalone
+      # download/upload scripts and to make dry run transition easier.
+      raise AttributeError('Please provide the bucket name without the gs:// '
+                           'prefix (e.g. %s)' % GMS_CLOUD_STORAGE)
+    bucket_path = 'gs://%s/%d' % (bucket_name, version_number)
+
+  return bucket_path
+
+
+class PlayServicesPaths(object):
+  '''
+  Describes the different paths to be used in the update process.
+
+         Filesystem hierarchy                        | Exposed property / notes
+  ---------------------------------------------------|-------------------------
+  [sdk_root]                                         | sdk_root / (1)
+   +- extras                                         |
+      +- google                                      |
+         +- google_play_services                     | package / (2)
+            +- source.properties                     | source_prop / (3)
+            +- LICENSE                               | license / (4)
+            +- google_play_services_library.zip.sha1 | lib_zip_sha1 / (5)
+            +- libproject                            |
+               +- google-play-services_lib           | lib / (6)
+                  +- res                             |
+                     +- values                       |
+                        +- version.xml               | version_xml (7)
+
+  Notes:
+
+   1. sdk_root: Path provided as a parameter to the script (--sdk_root)
+   2. package: This directory contains the Google Play services SDK itself.
+      When downloaded via the Android SDK manager, it will contain,
+      documentation, samples and other files in addition to the library. When
+      the update script downloads the library from our cloud storage, it is
+      cleared.
+   3. source_prop: File created by the Android SDK manager that contains
+      the package information, such as the version info and the license.
+   4. license: File created by the update script. Contains the license accepted
+      by the user.
+   5. lib_zip_sha1: sha1 of the library zip that has been installed by the
+      update script. It is compared with the one required by the config file to
+      check if an update is necessary.
+   6. lib: Contains the library itself: jar and resources. This is what is
+      downloaded from the cloud storage.
+   7. version_xml: File that contains the exact Google Play services library
+      version, the one that we track. The version looks like 811500, is used in
+      the code and the on-device APK, as opposed to the SDK package version
+      which looks like 27.0.0 and is used only by the Android SDK manager.
+
+  '''
+
+  def __init__(self, sdk_root):
+    relative_package = os.path.join('extras', 'google', 'google_play_services')
+    relative_lib = os.path.join(relative_package, 'libproject',
+                                'google-play-services_lib')
+    self.sdk_root = sdk_root
+
+    self.package = os.path.join(sdk_root, relative_package)
+    self.lib_zip_sha1 = os.path.join(self.package, ZIP_FILE_NAME + '.sha1')
+    self.license = os.path.join(self.package, LICENSE_FILE_NAME)
+    self.source_prop = os.path.join(self.package, 'source.properties')
+
+    self.lib = os.path.join(sdk_root, relative_lib)
+    self.version_xml = os.path.join(self.lib, 'res', 'values', 'version.xml')
+
+
+class DummyGsutil(download_from_google_storage.Gsutil):
+  '''
+  Class that replaces Gsutil to use a local directory instead of an online
+  bucket. It relies on the fact that Gsutil commands are very similar to shell
+  ones, so for the ones used here (ls, cp), it works to just use them with a
+  local directory.
+  '''
+
+  def __init__(self):
+    super(DummyGsutil, self).__init__(
+        download_from_google_storage.GSUTIL_DEFAULT_PATH)
+
+  def call(self, *args):
+    logging.debug('Calling command "%s"', str(args))
+    return cmd_helper.GetCmdStatusOutputAndError(args)
+
+  def check_call(self, *args):
+    logging.debug('Calling command "%s"', str(args))
+    return cmd_helper.GetCmdStatusOutputAndError(args)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/play_services/update_test.py b/build/android/play_services/update_test.py
new file mode 100755
index 0000000..b6898b6
--- /dev/null
+++ b/build/android/play_services/update_test.py
@@ -0,0 +1,414 @@
+#!/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.
+
+'''Unittests for update.py.
+
+They set up a temporary directory that is used to mock a bucket, the directory
+containing the configuration files and the android sdk directory.
+
+Tests run the script with various inputs and check the status of the filesystem
+'''
+
+import shutil
+import tempfile
+import unittest
+import os
+import sys
+import zipfile
+import contextlib
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from play_services import update
+
+
+class TestFunctions(unittest.TestCase):
+  DEFAULT_CONFIG_VERSION = 42
+  DEFAULT_LICENSE = 'Default License'
+  DEFAULT_ZIP_SHA1 = 'zip0and0filling0to0forty0chars0000000000'
+
+  def __init__(self, *args, **kwargs):
+    super(TestFunctions, self).__init__(*args, **kwargs)
+    self.paths = None  # Initialized in SetUpWorkdir
+    self.workdir = None  # Initialized in setUp
+
+  #override
+  def setUp(self):
+    self.workdir = tempfile.mkdtemp()
+
+  #override
+  def tearDown(self):
+    shutil.rmtree(self.workdir)
+    self.workdir = None
+
+  def testUpload(self):
+    version = 1337
+    self.SetUpWorkdir(
+        xml_version=version,
+        gms_lib=True,
+        source_prop=True)
+
+    status = update.main([
+        'upload',
+        '--dry-run',
+        '--skip-git',
+        '--bucket', self.paths.bucket,
+        '--config', self.paths.config_file,
+        '--sdk-root', self.paths.sdk_root
+    ])
+    self.assertEqual(status, 0, 'the command should have succeeded.')
+
+    # bucket should contain license, name = license.sha1
+    self.assertTrue(os.path.isfile(self.paths.config_license_sha1))
+    license_sha1 = _GetFileContent(self.paths.config_license_sha1)
+    bucket_license = os.path.join(self.paths.bucket, str(version),
+                                  license_sha1)
+    self.assertTrue(os.path.isfile(bucket_license))
+    self.assertEqual(_GetFileContent(bucket_license), self.DEFAULT_LICENSE)
+
+    # bucket should contain zip, name = zip.sha1
+    self.assertTrue(os.path.isfile(self.paths.config_zip_sha1))
+    bucket_zip = os.path.join(self.paths.bucket, str(version),
+                              _GetFileContent(self.paths.config_zip_sha1))
+    self.assertTrue(os.path.isfile(bucket_zip))
+
+    # unzip, should contain expected files
+    with zipfile.ZipFile(bucket_zip, "r") as bucket_zip_file:
+      self.assertEqual(bucket_zip_file.namelist(),
+                       ['dummy_file', 'res/values/version.xml'])
+
+  def testUploadAlreadyLatestVersion(self):
+    self.SetUpWorkdir(
+        xml_version=self.DEFAULT_CONFIG_VERSION,
+        gms_lib=True,
+        source_prop=True)
+
+    status = update.main([
+        'upload',
+        '--dry-run',
+        '--skip-git',
+        '--bucket', self.paths.bucket,
+        '--config', self.paths.config_file,
+        '--sdk-root', self.paths.sdk_root,
+    ])
+    self.assertEqual(status, 0, 'the command should have succeeded.')
+
+    # bucket should be empty
+    self.assertFalse(os.listdir(self.paths.bucket))
+    self.assertFalse(os.path.isfile(self.paths.config_license_sha1))
+    self.assertFalse(os.path.isfile(self.paths.config_zip_sha1))
+
+  def testDownload(self):
+    self.SetUpWorkdir(populate_bucket=True)
+
+    with _MockedInput('y'):
+      status = update.main([
+          'download',
+          '--dry-run',
+          '--bucket', self.paths.bucket,
+          '--config', self.paths.config_file,
+          '--sdk-root', self.paths.sdk_root,
+      ])
+
+    self.assertEqual(status, 0, 'the command should have succeeded.')
+
+    # sdk_root should contain zip contents, zip sha1, license
+    self.assertTrue(os.path.isfile(os.path.join(self.paths.gms_lib,
+                                                'dummy_file')))
+    self.assertTrue(os.path.isfile(self.paths.gms_root_sha1))
+    self.assertTrue(os.path.isfile(self.paths.gms_root_license))
+    self.assertEquals(_GetFileContent(self.paths.gms_root_license),
+                      self.DEFAULT_LICENSE)
+
+  def testDownloadBot(self):
+    self.SetUpWorkdir(populate_bucket=True, bot_env=True)
+
+    # No need to type 'y' on bots
+    status = update.main([
+        'download',
+        '--dry-run',
+        '--bucket', self.paths.bucket,
+        '--config', self.paths.config_file,
+        '--sdk-root', self.paths.sdk_root,
+    ])
+
+    self.assertEqual(status, 0, 'the command should have succeeded.')
+
+    # sdk_root should contain zip contents, zip sha1, license
+    self.assertTrue(os.path.isfile(os.path.join(self.paths.gms_lib,
+                                                'dummy_file')))
+    self.assertTrue(os.path.isfile(self.paths.gms_root_sha1))
+    self.assertTrue(os.path.isfile(self.paths.gms_root_license))
+    self.assertEquals(_GetFileContent(self.paths.gms_root_license),
+                      self.DEFAULT_LICENSE)
+
+  def testDownloadAlreadyUpToDate(self):
+    self.SetUpWorkdir(
+        populate_bucket=True,
+        existing_zip_sha1=self.DEFAULT_ZIP_SHA1)
+
+    status = update.main([
+        'download',
+        '--dry-run',
+        '--bucket', self.paths.bucket,
+        '--config', self.paths.config_file,
+        '--sdk-root', self.paths.sdk_root,
+    ])
+
+    self.assertEqual(status, 0, 'the command should have succeeded.')
+
+    # there should not be new files downloaded to sdk_root
+    self.assertFalse(os.path.isfile(os.path.join(self.paths.gms_lib,
+                                                 'dummy_file')))
+    self.assertFalse(os.path.isfile(self.paths.gms_root_license))
+
+  def testDownloadAcceptedLicense(self):
+    self.SetUpWorkdir(
+        populate_bucket=True,
+        existing_license=self.DEFAULT_LICENSE)
+
+    # License already accepted, no need to type
+    status = update.main([
+        'download',
+        '--dry-run',
+        '--bucket', self.paths.bucket,
+        '--config', self.paths.config_file,
+        '--sdk-root', self.paths.sdk_root,
+    ])
+
+    self.assertEqual(status, 0, 'the command should have succeeded.')
+
+    # sdk_root should contain zip contents, zip sha1, license
+    self.assertTrue(os.path.isfile(os.path.join(self.paths.gms_lib,
+                                                'dummy_file')))
+    self.assertTrue(os.path.isfile(self.paths.gms_root_sha1))
+    self.assertTrue(os.path.isfile(self.paths.gms_root_license))
+    self.assertEquals(_GetFileContent(self.paths.gms_root_license),
+                      self.DEFAULT_LICENSE)
+
+  def testDownloadNewLicense(self):
+    self.SetUpWorkdir(
+        populate_bucket=True,
+        existing_license='Old license')
+
+    with _MockedInput('y'):
+      status = update.main([
+          'download',
+          '--dry-run',
+          '--bucket', self.paths.bucket,
+          '--config', self.paths.config_file,
+          '--sdk-root', self.paths.sdk_root,
+      ])
+
+    self.assertEqual(status, 0, 'the command should have succeeded.')
+
+    # sdk_root should contain zip contents, zip sha1, NEW license
+    self.assertTrue(os.path.isfile(os.path.join(self.paths.gms_lib,
+                                                'dummy_file')))
+    self.assertTrue(os.path.isfile(self.paths.gms_root_sha1))
+    self.assertTrue(os.path.isfile(self.paths.gms_root_license))
+    self.assertEquals(_GetFileContent(self.paths.gms_root_license),
+                      self.DEFAULT_LICENSE)
+
+  def testDownloadRefusedLicense(self):
+    self.SetUpWorkdir(
+        populate_bucket=True,
+        existing_license='Old license')
+
+    with _MockedInput('n'):
+      status = update.main([
+          'download',
+          '--dry-run',
+          '--bucket', self.paths.bucket,
+          '--config', self.paths.config_file,
+          '--sdk-root', self.paths.sdk_root,
+      ])
+
+    self.assertEqual(status, 0, 'the command should have succeeded.')
+
+    # there should not be new files downloaded to sdk_root
+    self.assertFalse(os.path.isfile(os.path.join(self.paths.gms_lib,
+                                                 'dummy_file')))
+    self.assertEquals(_GetFileContent(self.paths.gms_root_license),
+                      'Old license')
+
+  def testDownloadNoAndroidSDK(self):
+    self.SetUpWorkdir(
+        populate_bucket=True,
+        existing_license='Old license')
+
+    non_existing_sdk_root = os.path.join(self.workdir, 'non_existing_sdk_root')
+    # Should not run, no typing needed
+    status = update.main([
+        'download',
+        '--dry-run',
+        '--bucket', self.paths.bucket,
+        '--config', self.paths.config_file,
+        '--sdk-root', non_existing_sdk_root,
+    ])
+
+    self.assertEqual(status, 0, 'the command should have succeeded.')
+    self.assertFalse(os.path.isdir(non_existing_sdk_root))
+
+  def SetUpWorkdir(self,
+                   bot_env=False,
+                   config_version=DEFAULT_CONFIG_VERSION,
+                   existing_license=None,
+                   existing_zip_sha1=None,
+                   gms_lib=False,
+                   populate_bucket=False,
+                   source_prop=None,
+                   xml_version=None):
+    '''Prepares workdir by putting it in the specified state
+
+    Args:
+      - general
+        bot_env: sets or unsets CHROME_HEADLESS
+
+      - bucket
+        populate_bucket: boolean. Populate the bucket with a zip and license
+                         file. The sha1s will be copied to the config directory
+
+      - config
+        config_version: number. Version of the current SDK. Defaults to
+                        `self.DEFAULT_CONFIG_VERSION`
+
+      - sdk_root
+        existing_license: string. Create a LICENSE file setting the specified
+                          text as content of the currently accepted license.
+        existing_zip_sha1: string. Create a sha1 file setting the specified
+                           hash as hash of the SDK supposed to be installed
+        gms_lib: boolean. Create a dummy file in the location of the play
+                 services SDK.
+        source_prop: boolean. Create a source.properties file that contains
+                     the license to upload.
+        xml_version: number. Create a version.xml file with the specified
+                     version that is used when uploading
+    '''
+    self.paths = Paths(self.workdir)
+
+    # Create the main directories
+    _MakeDirs(self.paths.sdk_root)
+    _MakeDirs(self.paths.config_dir)
+    _MakeDirs(self.paths.bucket)
+
+    # is not configured via argument.
+    update.SHA1_DIRECTORY = self.paths.config_dir
+
+    os.environ['CHROME_HEADLESS'] = '1' if bot_env else ''
+
+    if config_version:
+      _MakeDirs(os.path.dirname(self.paths.config_file))
+      with open(self.paths.config_file, 'w') as stream:
+        stream.write('{"version_number":%d}\n' % config_version)
+
+    if existing_license:
+      _MakeDirs(self.paths.gms_root)
+      with open(self.paths.gms_root_license, 'w') as stream:
+        stream.write(existing_license)
+
+    if existing_zip_sha1:
+      _MakeDirs(self.paths.gms_root)
+      with open(self.paths.gms_root_sha1, 'w') as stream:
+        stream.write(existing_zip_sha1)
+
+    if gms_lib:
+      _MakeDirs(self.paths.gms_lib)
+      with open(os.path.join(self.paths.gms_lib, 'dummy_file'), 'w') as stream:
+        stream.write('foo\n')
+
+    if source_prop:
+      _MakeDirs(os.path.dirname(self.paths.source_prop))
+      with open(self.paths.source_prop, 'w') as stream:
+        stream.write('Foo=Bar\n'
+                     'Pkg.License=%s\n'
+                     'Baz=Fizz\n' % self.DEFAULT_LICENSE)
+
+    if populate_bucket:
+      _MakeDirs(self.paths.config_dir)
+      bucket_dir = os.path.join(self.paths.bucket, str(config_version))
+      _MakeDirs(bucket_dir)
+
+      # TODO(dgn) should we use real sha1s? comparison with the real sha1 is
+      # done but does not do anything other than displaying a message.
+      config_license_sha1 = 'license0and0filling0to0forty0chars000000'
+      with open(self.paths.config_license_sha1, 'w') as stream:
+        stream.write(config_license_sha1)
+
+      with open(os.path.join(bucket_dir, config_license_sha1), 'w') as stream:
+        stream.write(self.DEFAULT_LICENSE)
+
+      config_zip_sha1 = self.DEFAULT_ZIP_SHA1
+      with open(self.paths.config_zip_sha1, 'w') as stream:
+        stream.write(config_zip_sha1)
+
+      pre_zip_lib = os.path.join(self.workdir, 'pre_zip_lib')
+      post_zip_lib = os.path.join(bucket_dir, config_zip_sha1)
+      _MakeDirs(pre_zip_lib)
+      with open(os.path.join(pre_zip_lib, 'dummy_file'), 'w') as stream:
+        stream.write('foo\n')
+      shutil.make_archive(post_zip_lib, 'zip', pre_zip_lib)
+      # make_archive appends .zip
+      shutil.move(post_zip_lib + '.zip', post_zip_lib)
+
+    if xml_version:
+      _MakeDirs(os.path.dirname(self.paths.xml_version))
+      with open(self.paths.xml_version, 'w') as stream:
+        stream.write(
+            '<?xml version="1.0" encoding="utf-8"?>\n'
+            '<resources>\n'
+            '    <integer name="google_play_services_version">%d</integer>\n'
+            '</resources>\n' % xml_version)
+
+
+class Paths(object):
+  '''Declaration of the paths commonly manipulated in the tests.'''
+
+  def __init__(self, workdir):
+    self.bucket = os.path.join(workdir, 'bucket')
+
+    self.config_dir = os.path.join(workdir, 'config')
+    self.config_file = os.path.join(self.config_dir, 'config.json')
+    self.config_license_sha1 = os.path.join(self.config_dir, 'LICENSE.sha1')
+    self.config_zip_sha1 = os.path.join(
+        self.config_dir,
+        'google_play_services_library.zip.sha1')
+
+    self.sdk_root = os.path.join(workdir, 'sdk_root')
+    self.gms_root = os.path.join(self.sdk_root, 'extras', 'google',
+                                 'google_play_services')
+    self.gms_root_sha1 = os.path.join(self.gms_root,
+                                      'google_play_services_library.zip.sha1')
+    self.gms_root_license = os.path.join(self.gms_root, 'LICENSE')
+    self.source_prop = os.path.join(self.gms_root, 'source.properties')
+    self.gms_lib = os.path.join(self.gms_root, 'libproject',
+                                'google-play-services_lib')
+    self.xml_version = os.path.join(self.gms_lib, 'res', 'values',
+                                    'version.xml')
+
+
+def _GetFileContent(file_path):
+  with open(file_path, 'r') as stream:
+    return stream.read()
+
+
+def _MakeDirs(path):
+  '''Avoids having to do the error handling everywhere.'''
+  if not os.path.exists(path):
+    os.makedirs(path)
+
+
+@contextlib.contextmanager
+def _MockedInput(typed_string):
+  '''Makes raw_input return |typed_string| while inside the context.'''
+  try:
+    original_raw_input = __builtins__.raw_input
+    __builtins__.raw_input = lambda _: typed_string
+    yield
+  finally:
+    __builtins__.raw_input = original_raw_input
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/play_services/utils.py b/build/android/play_services/utils.py
new file mode 100644
index 0000000..70b7fff
--- /dev/null
+++ b/build/android/play_services/utils.py
@@ -0,0 +1,113 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+'''
+Utility functions for all things related to manipulating google play services
+related files.
+'''
+
+import argparse
+import filecmp
+import json
+import logging
+import os
+import re
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from devil.utils import cmd_helper
+
+
+_XML_VERSION_NUMBER_PATTERN = re.compile(
+    r'<integer name="google_play_services_version">(\d+)<\/integer>')
+
+
+class DefaultsRawHelpFormatter(argparse.ArgumentDefaultsHelpFormatter,
+                               argparse.RawDescriptionHelpFormatter):
+  '''
+  Combines the features of RawDescriptionHelpFormatter and
+  ArgumentDefaultsHelpFormatter, providing defaults for the arguments and raw
+  text for the description.
+  '''
+  pass
+
+
+class ConfigParser(object):
+  '''Reads and writes the configuration files for play services related scripts
+
+  The configuration files are JSON files. Here is the data they are expected
+  to contain:
+
+   -  version_number
+      Number. Mirrors @integer/google_play_services_version from the library.
+      Example: 815000
+
+  '''
+  _VERSION_NUMBER_KEY = 'version_number'
+
+  def __init__(self, path):
+    self.path = path
+    self.data = {}
+
+    with open(path, 'r') as stream:
+      self.data = json.load(stream)
+
+  @property
+  def version_number(self):
+    return self.data[self._VERSION_NUMBER_KEY]
+
+  def UpdateVersionNumber(self, new_version_number):
+    '''Updates the version number and saves it in the configuration file. '''
+
+    with open(self.path, 'w') as stream:
+      self.data[self._VERSION_NUMBER_KEY] = new_version_number
+      json.dump(self.data, stream, sort_keys=True, indent=2)
+      stream.write(os.linesep)
+
+
+def FileEquals(expected_file, actual_file):
+  '''
+  Returns whether the two files are equal. Returns False if any of the files
+  doesn't exist.
+  '''
+
+  if not os.path.isfile(actual_file) or not os.path.isfile(expected_file):
+    return False
+  return filecmp.cmp(expected_file, actual_file)
+
+
+def IsRepoDirty(repo_root):
+  '''Returns True if there are no staged or modified files, False otherwise.'''
+
+  # diff-index returns 1 if there are staged changes or modified files,
+  # 0 otherwise
+  cmd = ['git', 'diff-index', '--quiet', 'HEAD']
+  return cmd_helper.Call(cmd, cwd=repo_root) == 1
+
+
+def GetVersionNumberFromLibraryResources(version_xml):
+  '''
+  Extracts a Google Play services version number from its version.xml file.
+  '''
+
+  with open(version_xml, 'r') as version_file:
+    version_file_content = version_file.read()
+
+  match = _XML_VERSION_NUMBER_PATTERN.search(version_file_content)
+  if not match:
+    raise AttributeError('A value for google_play_services_version was not '
+                         'found in ' + version_xml)
+  return int(match.group(1))
+
+
+def MakeLocalCommit(repo_root, files_to_commit, message):
+  '''Makes a local git commit.'''
+
+  logging.debug('Staging files (%s) for commit.', files_to_commit)
+  if cmd_helper.Call(['git', 'add'] + files_to_commit, cwd=repo_root) != 0:
+    raise Exception('The local commit failed.')
+
+  logging.debug('Committing.')
+  if cmd_helper.Call(['git', 'commit', '-m', message], cwd=repo_root) != 0:
+    raise Exception('The local commit failed.')
diff --git a/build/android/preprocess_google_play_services.config.json b/build/android/preprocess_google_play_services.config.json
new file mode 100644
index 0000000..a8de9bf
--- /dev/null
+++ b/build/android/preprocess_google_play_services.config.json
@@ -0,0 +1,59 @@
+{
+  "lib_version": "7.3.0",
+  "clients": [
+    "play-services-base",
+    "play-services-cast",
+    "play-services-identity"
+  ],
+  "base_client": "play-services-base",
+  "_comment": [
+    "For the list of locales to keep, generate an android build and list ",
+    "out/Debug/gen/chrome/java/res, or look at the android section in ",
+    "//chrome/app/generated_resources.grd"
+  ],
+  "locale_whitelist": [
+    "am",
+    "ar",
+    "bg",
+    "ca",
+    "cs",
+    "da",
+    "de",
+    "el",
+    "en-rGB",
+    "es",
+    "es-rUS",
+    "fa",
+    "fi",
+    "fr",
+    "hi",
+    "hr",
+    "hu",
+    "in",
+    "it",
+    "iw",
+    "ja",
+    "ko",
+    "lt",
+    "lv",
+    "nb",
+    "nl",
+    "pl",
+    "pt-rBR",
+    "pt-rPT",
+    "ro",
+    "ru",
+    "sk",
+    "sl",
+    "sr",
+    "sv",
+    "sw",
+    "th",
+    "tl",
+    "tr",
+    "uk",
+    "vi",
+    "zh-rCN",
+    "zh-rTW"
+  ]
+}
diff --git a/build/android/preprocess_google_play_services.py b/build/android/preprocess_google_play_services.py
new file mode 100755
index 0000000..eb106a1
--- /dev/null
+++ b/build/android/preprocess_google_play_services.py
@@ -0,0 +1,299 @@
+#!/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.
+
+'''Prepares the Google Play services split client libraries before usage by
+Chrome's build system.
+
+We need to preprocess Google Play services before using it in Chrome
+builds for 2 main reasons:
+
+- Getting rid of unused resources: unsupported languages, unused
+drawables, etc.
+
+- Merging the differents jars so that it can be proguarded more
+easily. This is necessary since debug and test apks get very close
+to the dex limit.
+
+The script is supposed to be used with the maven repository that can be
+obtained by downloading the "extra-google-m2repository" from the Android SDK
+Manager. It also supports importing from already extracted AAR files using the
+--is-extracted-repo flag. The expected directory structure in that case would
+look like:
+
+    REPOSITORY_DIR
+    +-- CLIENT_1
+    |   +-- <content of the first AAR file>
+    +-- CLIENT_2
+    +-- etc.
+
+The json config (see the -c argument) file should provide the following fields:
+
+- lib_version: String. Used when building from the maven repository. It should
+  be the package's version (e.g. "7.3.0"). Unused with extracted repositories.
+
+- clients: String array. List of clients to pick. For example, when building
+  from the maven repository, it's the artifactId (e.g. "play-services-base") of
+  each client. With an extracted repository, it's the name of the
+  subdirectories.
+
+- locale_whitelist: String array. Locales that should be allowed in the final
+  resources. They are specified the same way they are appended to the `values`
+  directory in android resources (e.g. "us-GB", "it", "fil").
+
+The output is a directory with the following structure:
+
+    OUT_DIR
+    +-- google-play-services.jar
+    +-- res
+    |   +-- CLIENT_1
+    |   |   +-- color
+    |   |   +-- values
+    |   |   +-- etc.
+    |   +-- CLIENT_2
+    |       +-- ...
+    +-- stub
+        +-- res/[.git-keep-directory]
+        +-- src/android/UnusedStub.java
+
+Requires the `jar` utility in the path.
+
+'''
+
+import argparse
+import glob
+import itertools
+import json
+import os
+import re
+import shutil
+import stat
+import sys
+
+from datetime import datetime
+from devil.utils import cmd_helper
+from pylib import constants
+
+sys.path.append(
+    os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android', 'gyp'))
+from util import build_utils # pylint: disable=import-error
+
+
+M2_PKG_PATH = os.path.join('com', 'google', 'android', 'gms')
+OUTPUT_FORMAT_VERSION = 1
+VERSION_FILE_NAME = 'version_info.json'
+VERSION_NUMBER_PATTERN = re.compile(
+    r'<integer name="google_play_services_version">(\d+)<\/integer>')
+
+def main():
+  parser = argparse.ArgumentParser(description=("Prepares the Google Play "
+      "services split client libraries before usage by Chrome's build system. "
+      "See the script's documentation for more a detailed help."))
+  parser.add_argument('-r',
+                      '--repository',
+                      help='The Google Play services repository location',
+                      required=True,
+                      metavar='FILE')
+  parser.add_argument('-o',
+                      '--out-dir',
+                      help='The output directory',
+                      required=True,
+                      metavar='FILE')
+  parser.add_argument('-c',
+                      '--config-file',
+                      help='Config file path',
+                      required=True,
+                      metavar='FILE')
+  parser.add_argument('-x',
+                      '--is-extracted-repo',
+                      action='store_true',
+                      default=False,
+                      help='The provided repository is not made of AAR files.')
+
+  args = parser.parse_args()
+
+  ProcessGooglePlayServices(args.repository,
+                            args.out_dir,
+                            args.config_file,
+                            args.is_extracted_repo)
+
+
+def ProcessGooglePlayServices(repo, out_dir, config_path, is_extracted_repo):
+  with open(config_path, 'r') as json_file:
+    config = json.load(json_file)
+
+  with build_utils.TempDir() as tmp_root:
+    tmp_paths = _SetupTempDir(tmp_root)
+
+    if is_extracted_repo:
+      _ImportFromExtractedRepo(config, tmp_paths, repo)
+    else:
+      _ImportFromAars(config, tmp_paths, repo)
+
+    _GenerateCombinedJar(tmp_paths)
+    _ProcessResources(config, tmp_paths)
+
+    if is_extracted_repo:
+      printable_repo = repo
+    else:
+      printable_repo = 'm2repository - ' + config['lib_version']
+    _BuildOutput(config, tmp_paths, out_dir, printable_repo)
+
+
+def _SetupTempDir(tmp_root):
+  tmp_paths = {
+    'root': tmp_root,
+    'imported_clients': os.path.join(tmp_root, 'imported_clients'),
+    'extracted_jars': os.path.join(tmp_root, 'jar'),
+    'combined_jar': os.path.join(tmp_root, 'google-play-services.jar'),
+  }
+  os.mkdir(tmp_paths['imported_clients'])
+  os.mkdir(tmp_paths['extracted_jars'])
+
+  return tmp_paths
+
+
+def _SetupOutputDir(out_dir):
+  out_paths = {
+    'root': out_dir,
+    'res': os.path.join(out_dir, 'res'),
+    'jar': os.path.join(out_dir, 'google-play-services.jar'),
+    'stub': os.path.join(out_dir, 'stub'),
+  }
+
+  shutil.rmtree(out_paths['jar'], ignore_errors=True)
+  shutil.rmtree(out_paths['res'], ignore_errors=True)
+  shutil.rmtree(out_paths['stub'], ignore_errors=True)
+
+  return out_paths
+
+
+def _MakeWritable(dir_path):
+  for root, dirs, files in os.walk(dir_path):
+    for path in itertools.chain(dirs, files):
+      st = os.stat(os.path.join(root, path))
+      os.chmod(os.path.join(root, path), st.st_mode | stat.S_IWUSR)
+
+
+def _ImportFromAars(config, tmp_paths, repo):
+  for client in config['clients']:
+    aar_name = '%s-%s.aar' % (client, config['lib_version'])
+    aar_path = os.path.join(repo, M2_PKG_PATH, client,
+                            config['lib_version'], aar_name)
+    aar_out_path = os.path.join(tmp_paths['imported_clients'], client)
+    build_utils.ExtractAll(aar_path, aar_out_path)
+
+    client_jar_path = os.path.join(aar_out_path, 'classes.jar')
+    build_utils.ExtractAll(client_jar_path, tmp_paths['extracted_jars'],
+                           no_clobber=False)
+
+
+def _ImportFromExtractedRepo(config, tmp_paths, repo):
+  # Import the clients
+  try:
+    for client in config['clients']:
+      client_out_dir = os.path.join(tmp_paths['imported_clients'], client)
+      shutil.copytree(os.path.join(repo, client), client_out_dir)
+
+      client_jar_path = os.path.join(client_out_dir, 'classes.jar')
+      build_utils.ExtractAll(client_jar_path, tmp_paths['extracted_jars'],
+                             no_clobber=False)
+  finally:
+    _MakeWritable(tmp_paths['imported_clients'])
+
+
+def _GenerateCombinedJar(tmp_paths):
+  out_file_name = tmp_paths['combined_jar']
+  working_dir = tmp_paths['extracted_jars']
+  cmd_helper.Call(['jar', '-cf', out_file_name, '-C', working_dir, '.'])
+
+
+def _ProcessResources(config, tmp_paths):
+  LOCALIZED_VALUES_BASE_NAME = 'values-'
+  locale_whitelist = set(config['locale_whitelist'])
+
+  glob_pattern = os.path.join(tmp_paths['imported_clients'], '*', 'res', '*')
+  for res_dir in glob.glob(glob_pattern):
+    dir_name = os.path.basename(res_dir)
+
+    if dir_name.startswith('drawable'):
+      shutil.rmtree(res_dir)
+      continue
+
+    if dir_name.startswith(LOCALIZED_VALUES_BASE_NAME):
+      dir_locale = dir_name[len(LOCALIZED_VALUES_BASE_NAME):]
+      if dir_locale not in locale_whitelist:
+        shutil.rmtree(res_dir)
+
+
+def _GetVersionNumber(config, tmp_paths):
+  version_file_path = os.path.join(tmp_paths['imported_clients'],
+                                   config['base_client'],
+                                   'res',
+                                   'values',
+                                   'version.xml')
+
+  with open(version_file_path, 'r') as version_file:
+    version_file_content = version_file.read()
+
+  match = VERSION_NUMBER_PATTERN.search(version_file_content)
+  if not match:
+    raise AttributeError('A value for google_play_services_version was not '
+                         'found in ' + version_file_path)
+
+  return match.group(1)
+
+
+def _BuildOutput(config, tmp_paths, out_dir, printable_repo):
+  generation_date = datetime.utcnow()
+  play_services_full_version = _GetVersionNumber(config, tmp_paths)
+
+  # Create a version text file to allow quickly checking the version
+  gen_info = {
+    '@Description@': 'Preprocessed Google Play services clients for chrome',
+    'Generator script': os.path.basename(__file__),
+    'Repository source': printable_repo,
+    'Library version': play_services_full_version,
+    'Directory format version': OUTPUT_FORMAT_VERSION,
+    'Generation Date (UTC)': str(generation_date)
+  }
+  tmp_version_file_path = os.path.join(tmp_paths['root'], VERSION_FILE_NAME)
+  with open(tmp_version_file_path, 'w') as version_file:
+    json.dump(gen_info, version_file, indent=2, sort_keys=True)
+
+  out_paths = _SetupOutputDir(out_dir)
+
+  # Copy the resources to the output dir
+  for client in config['clients']:
+    res_in_tmp_dir = os.path.join(tmp_paths['imported_clients'], client, 'res')
+    if os.path.isdir(res_in_tmp_dir) and os.listdir(res_in_tmp_dir):
+      res_in_final_dir = os.path.join(out_paths['res'], client)
+      shutil.copytree(res_in_tmp_dir, res_in_final_dir)
+
+  # Copy the jar
+  shutil.copyfile(tmp_paths['combined_jar'], out_paths['jar'])
+
+  # Write the java dummy stub. Needed for gyp to create the resource jar
+  stub_location = os.path.join(out_paths['stub'], 'src', 'android')
+  os.makedirs(stub_location)
+  with open(os.path.join(stub_location, 'UnusedStub.java'), 'w') as stub:
+    stub.write('package android;'
+               'public final class UnusedStub {'
+               '    private UnusedStub() {}'
+               '}')
+
+  # Create the main res directory. It is needed by gyp
+  stub_res_location = os.path.join(out_paths['stub'], 'res')
+  os.makedirs(stub_res_location)
+  with open(os.path.join(stub_res_location, '.res-stamp'), 'w') as stamp:
+    content_str = 'google_play_services_version: %s\nutc_date: %s\n'
+    stamp.write(content_str % (play_services_full_version, generation_date))
+
+  shutil.copyfile(tmp_version_file_path,
+                  os.path.join(out_paths['root'], VERSION_FILE_NAME))
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/provision_devices.py b/build/android/provision_devices.py
index 259bd55..3a2e100 100755
--- a/build/android/provision_devices.py
+++ b/build/android/provision_devices.py
@@ -11,6 +11,8 @@
 """
 
 import argparse
+import datetime
+import json
 import logging
 import os
 import posixpath
@@ -19,18 +21,20 @@
 import sys
 import time
 
+from devil.android import battery_utils
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_temp_file
+from devil.android import device_utils
+from devil.android.sdk import version_codes
+from devil.utils import run_tests_helper
+from devil.utils import timeout_retry
 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
+_SYSTEM_WEBVIEW_PATHS = ['/system/app/webview', '/system/app/WebViewGoogle']
+_CHROME_PACKAGE_REGEX = re.compile('.*chrom.*')
+_TOMBSTONE_REGEX = re.compile('tombstone.*')
 
 
 class _DEFAULT_TIMEOUTS(object):
@@ -49,28 +53,36 @@
   ALL = [WIPE, PROPERTIES, FINISH]
 
 
-def ProvisionDevices(options):
-  devices = device_utils.DeviceUtils.HealthyDevices()
-  if options.device:
-    devices = [d for d in devices if d == options.device]
-    if not devices:
-      raise device_errors.DeviceUnreachableError(options.device)
-
+def ProvisionDevices(args):
+  blacklist = (device_blacklist.Blacklist(args.blacklist_file)
+               if args.blacklist_file
+               else None)
+  devices = [d for d in device_utils.DeviceUtils.HealthyDevices(blacklist)
+             if not args.emulators or d.adb.is_emulator]
+  if args.device:
+    devices = [d for d in devices if d == args.device]
+  if not devices:
+    raise device_errors.DeviceUnreachableError(args.device)
   parallel_devices = device_utils.DeviceUtils.parallel(devices)
-  parallel_devices.pMap(ProvisionDevice, options)
-  if options.auto_reconnect:
+  if args.emulators:
+    parallel_devices.pMap(SetProperties, args)
+  else:
+    parallel_devices.pMap(ProvisionDevice, blacklist, args)
+  if args.auto_reconnect:
     _LaunchHostHeartbeat()
-  blacklist = device_blacklist.ReadBlacklist()
-  if all(d in blacklist for d in devices):
+  blacklisted_devices = blacklist.Read() if blacklist else []
+  if args.output_device_blacklist:
+    with open(args.output_device_blacklist, 'w') as f:
+      json.dump(blacklisted_devices, f)
+  if all(d in blacklisted_devices for d in devices):
     raise device_errors.NoDevicesError
   return 0
 
 
-def ProvisionDevice(device, options):
+def ProvisionDevice(device, blacklist, options):
   if options.reboot_timeout:
     reboot_timeout = options.reboot_timeout
-  elif (device.build_version_sdk >=
-        constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
+  elif device.build_version_sdk >= version_codes.LOLLIPOP:
     reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP
   else:
     reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP
@@ -79,7 +91,11 @@
     return not options.phases or phase_name in options.phases
 
   def run_phase(phase_func, reboot=True):
-    device.WaitUntilFullyBooted(timeout=reboot_timeout)
+    try:
+      device.WaitUntilFullyBooted(timeout=reboot_timeout, retries=0)
+    except device_errors.CommandTimeoutError:
+      logging.error('Device did not finish booting. Will try to reboot.')
+      device.Reboot(timeout=reboot_timeout)
     phase_func(device, options)
     if reboot:
       device.Reboot(False, retries=0)
@@ -87,7 +103,10 @@
 
   try:
     if should_run_phase(_PHASES.WIPE):
-      run_phase(WipeDevice)
+      if options.chrome_specific_wipe:
+        run_phase(WipeChromeData)
+      else:
+        run_phase(WipeDevice)
 
     if should_run_phase(_PHASES.PROPERTIES):
       run_phase(SetProperties)
@@ -95,16 +114,81 @@
     if should_run_phase(_PHASES.FINISH):
       run_phase(FinishProvisioning, reboot=False)
 
-  except (errors.WaitForResponseTimedOutError,
-          device_errors.CommandTimeoutError):
+    if options.chrome_specific_wipe:
+      package = "com.google.android.gms"
+      version_name = device.GetApplicationVersion(package)
+      logging.info("Version name for %s is %s", package, version_name)
+
+    CheckExternalStorage(device)
+
+  except device_errors.CommandTimeoutError:
     logging.exception('Timed out waiting for device %s. Adding to blacklist.',
                       str(device))
-    device_blacklist.ExtendBlacklist([str(device)])
+    if blacklist:
+      blacklist.Extend([str(device)], reason='provision_timeout')
 
   except device_errors.CommandFailedError:
     logging.exception('Failed to provision device %s. Adding to blacklist.',
                       str(device))
-    device_blacklist.ExtendBlacklist([str(device)])
+    if blacklist:
+      blacklist.Extend([str(device)], reason='provision_failure')
+
+def CheckExternalStorage(device):
+  """Checks that storage is writable and if not makes it writable.
+
+  Arguments:
+    device: The device to check.
+  """
+  try:
+    with device_temp_file.DeviceTempFile(
+        device.adb, suffix='.sh', dir=device.GetExternalStoragePath()) as f:
+      device.WriteFile(f.name, 'test')
+  except device_errors.CommandFailedError:
+    logging.info('External storage not writable. Remounting / as RW')
+    device.RunShellCommand(['mount', '-o', 'remount,rw', '/'],
+                           check_return=True, as_root=True)
+    device.EnableRoot()
+    with device_temp_file.DeviceTempFile(
+        device.adb, suffix='.sh', dir=device.GetExternalStoragePath()) as f:
+      device.WriteFile(f.name, 'test')
+
+def WipeChromeData(device, options):
+  """Wipes chrome specific data from device
+
+  (1) uninstall any app whose name matches *chrom*, except
+      com.android.chrome, which is the chrome stable package. Doing so also
+      removes the corresponding dirs under /data/data/ and /data/app/
+  (2) remove any dir under /data/app-lib/ whose name matches *chrom*
+  (3) remove any files under /data/tombstones/ whose name matches "tombstone*"
+  (4) remove /data/local.prop if there is any
+  (5) remove /data/local/chrome-command-line if there is any
+  (6) remove anything under /data/local/.config/ if the dir exists
+      (this is telemetry related)
+  (7) remove anything under /data/local/tmp/
+
+  Arguments:
+    device: the device to wipe
+  """
+  if options.skip_wipe:
+    return
+
+  try:
+    device.EnableRoot()
+    _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX,
+                      constants.PACKAGE_INFO['chrome_stable'].package)
+    _WipeUnderDirIfMatch(device, '/data/app-lib/', _CHROME_PACKAGE_REGEX)
+    _WipeUnderDirIfMatch(device, '/data/tombstones/', _TOMBSTONE_REGEX)
+
+    _WipeFileOrDir(device, '/data/local.prop')
+    _WipeFileOrDir(device, '/data/local/chrome-command-line')
+    _WipeFileOrDir(device, '/data/local/.config/')
+    _WipeFileOrDir(device, '/data/local/tmp/')
+
+    device.RunShellCommand('rm -rf %s/*' % device.GetExternalStoragePath(),
+                           check_return=True)
+  except device_errors.CommandFailedError:
+    logging.exception('Possible failure while wiping the device. '
+                      'Attempting to continue.')
 
 
 def WipeDevice(device, options):
@@ -140,7 +224,7 @@
             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)
+          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. '
@@ -173,24 +257,35 @@
   else:
     device_settings.ConfigureContentSettings(
         device, device_settings.ENABLE_LOCATION_SETTINGS)
+
+  if options.disable_mock_location:
+    device_settings.ConfigureContentSettings(
+        device, device_settings.DISABLE_MOCK_LOCATION_SETTINGS)
+  else:
+    device_settings.ConfigureContentSettings(
+        device, device_settings.ENABLE_MOCK_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.disable_system_chrome:
+    # The system chrome version on the device interferes with some tests.
+    device.RunShellCommand(['pm', 'disable', 'com.android.chrome'],
+                           check_return=True)
 
-  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.')
+  if options.remove_system_webview:
+    if device.HasRoot():
+      # This is required, e.g., to replace the system webview on a device.
+      device.adb.Remount()
+      device.RunShellCommand(['stop'], check_return=True)
+      device.RunShellCommand(['rm', '-rf'] + _SYSTEM_WEBVIEW_PATHS,
+                             check_return=True)
+      device.RunShellCommand(['start'], check_return=True)
+    else:
+      logging.warning('Cannot remove system webview from a non-rooted device')
+
 
 def _ConfigureLocalProperties(device, java_debug=True):
   """Set standard readonly testing device properties prior to reboot."""
@@ -207,27 +302,89 @@
     local_props.append('debug.checkjni=1')
   try:
     device.WriteFile(
-        constants.DEVICE_LOCAL_PROPERTIES_PATH,
+        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],
+        ['chmod', '644', 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)
+  if options.min_battery_level is not None:
+    try:
+      battery = battery_utils.BatteryUtils(device)
+      battery.ChargeDeviceToLevel(options.min_battery_level)
+    except device_errors.CommandFailedError:
+      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:
+      logging.exception('Unable to let battery cool to specified temperature.')
+
+  def _set_and_verify_date():
+    if device.build_version_sdk >= version_codes.MARSHMALLOW:
+      date_format = '%m%d%H%M%Y.%S'
+      set_date_command = ['date']
+    else:
+      date_format = '%Y%m%d.%H%M%S'
+      set_date_command = ['date', '-s']
+    strgmtime = time.strftime(date_format, time.gmtime())
+    set_date_command.append(strgmtime)
+    device.RunShellCommand(set_date_command, as_root=True, check_return=True)
+
+    device_time = device.RunShellCommand(
+        ['date', '+"%Y%m%d.%H%M%S"'], as_root=True,
+        single_line=True).replace('"', '')
+    device_time = datetime.datetime.strptime(device_time, "%Y%m%d.%H%M%S")
+    correct_time = datetime.datetime.strptime(strgmtime, date_format)
+    tdelta = (correct_time - device_time).seconds
+    if tdelta <= 1:
+      logging.info('Date/time successfully set on %s', device)
+      return True
+    else:
+      logging.error('Date mismatch. Device: %s Correct: %s',
+                    device_time.isoformat(), correct_time.isoformat())
+      return False
+
+  # Sometimes the date is not set correctly on the devices. Retry on failure.
+  if not timeout_retry.WaitFor(_set_and_verify_date, wait_period=1,
+                               max_tries=2):
+    raise device_errors.CommandFailedError(
+        'Failed to set date & time.', device_serial=str(device))
+
   props = device.RunShellCommand('getprop', check_return=True)
   for prop in props:
-    logging.info('  %s' % prop)
+    logging.info('  %s', prop)
   if options.auto_reconnect:
     _PushAndLaunchAdbReboot(device, options.target)
 
 
+def _UninstallIfMatch(device, pattern, app_to_keep):
+  installed_packages = device.RunShellCommand(['pm', 'list', 'packages'])
+  for package_output in installed_packages:
+    package = package_output.split(":")[1]
+    if pattern.match(package) and not package == app_to_keep:
+      device.Uninstall(package)
+
+
+def _WipeUnderDirIfMatch(device, path, pattern):
+  ls_result = device.Ls(path)
+  for (content, _) in ls_result:
+    if pattern.match(content):
+      _WipeFileOrDir(device, path + content)
+
+
+def _WipeFileOrDir(device, path):
+  if device.PathExists(path):
+    device.RunShellCommand(['rm', '-rf', path], check_return=True)
+
+
 def _PushAndLaunchAdbReboot(device, target):
   """Pushes and launches the adb_reboot binary on the device.
 
@@ -237,7 +394,7 @@
     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))
+  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
@@ -260,7 +417,6 @@
   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()
@@ -270,7 +426,6 @@
     pid = re.findall(r'(\S+)', match)[1]
     subprocess.call(['kill', str(pid)])
 
-
 def main():
   # Recommended options on perf bots:
   # --disable-network
@@ -286,6 +441,7 @@
   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('--blacklist-file', help='Device blacklist JSON file.')
   parser.add_argument('--phase', action='append', choices=_PHASES.ALL,
                       dest='phases',
                       help='Phases of provisioning to run. '
@@ -301,11 +457,17 @@
                       ' level before trying to continue')
   parser.add_argument('--disable-location', action='store_true',
                       help='disable Google location services on devices')
+  parser.add_argument('--disable-mock-location', action='store_true',
+                      default=False, help='Set ALLOW_MOCK_LOCATION to false')
   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('--disable-system-chrome', action='store_true',
+                      help='Disable the system chrome from devices.')
+  parser.add_argument('--remove-system-webview', action='store_true',
+                      help='Remove the system webview from devices.')
   parser.add_argument('-t', '--target', default='Debug',
                       help='the build target (default: %(default)s)')
   parser.add_argument('-r', '--auto-reconnect', action='store_true',
@@ -317,6 +479,12 @@
                       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.')
+  parser.add_argument('--output-device-blacklist',
+                      help='Json file to output the device blacklist.')
+  parser.add_argument('--chrome-specific-wipe', action='store_true',
+                      help='only wipe chrome specific data during provisioning')
+  parser.add_argument('--emulators', action='store_true',
+                      help='provision only emulators and ignore usb devices')
   args = parser.parse_args()
   constants.SetBuildType(args.target)
 
diff --git a/build/android/push_libraries.gypi b/build/android/push_libraries.gypi
index c96e5a5..a4a6fcd 100644
--- a/build/android/push_libraries.gypi
+++ b/build/android/push_libraries.gypi
@@ -32,7 +32,7 @@
     '<(strip_stamp)',
     '<(strip_additional_stamp)',
     '<(build_device_config_path)',
-    '<(pack_arm_relocations_stamp)',
+    '<(pack_relocations_stamp)',
   ],
   'outputs': [
     '<(push_stamp)',
@@ -44,6 +44,6 @@
     '--device-dir=<(device_library_dir)',
     '--libraries=@FileArg(<(ordered_libraries_file):libraries)',
     '--stamp=<(push_stamp)',
-    '--configuration-name=<(configuration_name)',
+    '--configuration-name=<(CONFIGURATION_NAME)',
   ],
 }
diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py
deleted file mode 100644
index f7191f7..0000000
--- a/build/android/pylib/android_commands.py
+++ /dev/null
@@ -1,1976 +0,0 @@
-# Copyright (c) 2012 The Chromium 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.
-
-Note that this module is deprecated.
-"""
-# TODO(jbudorick): Delete this file once no clients use it.
-
-# 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
deleted file mode 100644
index 21c34f9..0000000
--- a/build/android/pylib/android_commands_unittest.py
+++ /dev/null
@@ -1,191 +0,0 @@
-# Copyright 2014 The Chromium 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/base_setup.py b/build/android/pylib/base/base_setup.py
index 0b0daf1..84441dc 100644
--- a/build/android/pylib/base/base_setup.py
+++ b/build/android/pylib/base/base_setup.py
@@ -43,7 +43,7 @@
       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 = isolator.Isolator()
   i.Clear()
   i.Remap(isolate_abs_path, isolated_abs_path)
   # We're relying on the fact that timestamps are preserved
@@ -56,10 +56,8 @@
   return i
 
 
-def PushDataDeps(device, device_dir, test_options):
+def PushDataDeps(device, host_dir, 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)])
+  if os.path.exists(host_dir):
+    device.PushChangedFiles([(host_dir, device_dir)],
+                            delete_device_stale=test_options.delete_stale_data)
diff --git a/build/android/pylib/base/base_test_result.py b/build/android/pylib/base/base_test_result.py
index 58200f6..af4b71c 100644
--- a/build/android/pylib/base/base_test_result.py
+++ b/build/android/pylib/base/base_test_result.py
@@ -4,6 +4,9 @@
 
 """Module containing base test results classes."""
 
+import threading
+
+
 class ResultType(object):
   """Class enumerating test types."""
   PASS = 'PASS'
@@ -91,60 +94,64 @@
 
   def __init__(self):
     self._results = set()
+    self._results_lock = threading.RLock()
 
   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)
+    with self._results_lock:
+      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')
+    with self._results_lock:
+      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()))))
+      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))
+      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)
+      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])
+    with self._results_lock:
+      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()
+    return self.GetGtestForm()
 
   def AddResult(self, result):
     """Add |result| to the set.
@@ -153,7 +160,8 @@
       result: An instance of BaseTestResult.
     """
     assert isinstance(result, BaseTestResult)
-    self._results.add(result)
+    with self._results_lock:
+      self._results.add(result)
 
   def AddResults(self, results):
     """Add |results| to the set.
@@ -161,8 +169,9 @@
     Args:
       results: An iterable of BaseTestResult objects.
     """
-    for t in results:
-      self.AddResult(t)
+    with self._results_lock:
+      for t in results:
+        self.AddResult(t)
 
   def AddTestRunResults(self, results):
     """Add the set of test results from |results|.
@@ -171,16 +180,19 @@
       results: An instance of TestRunResults.
     """
     assert isinstance(results, TestRunResults)
-    # pylint: disable=W0212
-    self._results.update(results._results)
+    with self._results_lock:
+      # pylint: disable=W0212
+      self._results.update(results._results)
 
   def GetAll(self):
     """Get the set of all test results."""
-    return self._results.copy()
+    with self._results_lock:
+      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)
+    with self._results_lock:
+      return set(t for t in self._results if t.GetType() == test_type)
 
   def GetPass(self):
     """Get the set of all passed test results."""
diff --git a/build/android/pylib/base/base_test_runner.py b/build/android/pylib/base/base_test_runner.py
index 2a7fdd3..1be178b 100644
--- a/build/android/pylib/base/base_test_runner.py
+++ b/build/android/pylib/base/base_test_runner.py
@@ -10,8 +10,8 @@
 
 import logging
 
-from pylib import ports
-from pylib.device import device_utils
+from devil.android import device_utils
+from devil.android import ports
 from pylib.forwarder import Forwarder
 from pylib.valgrind_tools import CreateTool
 # TODO(frankf): Move this to pylib/utils
diff --git a/build/android/pylib/base/test_dispatcher.py b/build/android/pylib/base/test_dispatcher.py
index f919965..8152bea 100644
--- a/build/android/pylib/base/test_dispatcher.py
+++ b/build/android/pylib/base/test_dispatcher.py
@@ -21,12 +21,12 @@
 import logging
 import threading
 
+from devil.android import device_errors
+from devil.utils import reraiser_thread
+from devil.utils import watchdog_timer
 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
@@ -171,7 +171,8 @@
   Returns:
     A tuple of (TestRunResults object, exit code)
   """
-  logging.warning('Running tests with %s test runners.' % (len(runners)))
+  logging.warning('Running tests with %s test %s.',
+                  len(runners), 'runners' if len(runners) != 1 else 'runner')
   results = []
   exit_code = 0
   run_results = base_test_result.TestRunResults()
@@ -188,14 +189,17 @@
   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)
+  except device_errors.CommandFailedError:
+    logging.exception('Command failed on device.')
+  except device_errors.CommandFailedError:
+    logging.exception('Command timed out on device.')
+  except device_errors.DeviceUnreachableError:
+    logging.exception('Device became unreachable.')
 
   if not all((len(tc) == 0 for tc in test_collections)):
-    logging.error('Only ran %d tests (all devices are likely offline).' %
+    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(
@@ -223,7 +227,8 @@
   Returns:
     A list of TestRunner objects.
   """
-  logging.warning('Creating %s test runners.' % len(devices))
+  logging.warning('Creating %s test %s.', len(devices),
+                  'runners' if len(devices) != 1 else 'runner')
   runners = []
   counter = _ThreadSafeCounter()
   threads = reraiser_thread.ReraiserThreadGroup(
@@ -328,5 +333,5 @@
       _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))
+    except Exception: # pylint: disable=broad-except
+      logging.exception('Unexpected exception caught during TearDown')
diff --git a/build/android/pylib/base/test_dispatcher_unittest.py b/build/android/pylib/base/test_dispatcher_unittest.py
index cace9a6..57f271f 100755
--- a/build/android/pylib/base/test_dispatcher_unittest.py
+++ b/build/android/pylib/base/test_dispatcher_unittest.py
@@ -12,17 +12,17 @@
 import unittest
 
 
+from devil.android import device_utils
+from devil.android.sdk import adb_wrapper
+from devil.utils import watchdog_timer
 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
+import mock # pylint: disable=import-error
 
 
 class TestException(Exception):
diff --git a/build/android/pylib/base/test_instance_factory.py b/build/android/pylib/base/test_instance_factory.py
index 7e7cb0c..523b4c5 100644
--- a/build/android/pylib/base/test_instance_factory.py
+++ b/build/android/pylib/base/test_instance_factory.py
@@ -2,22 +2,20 @@
 # 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
-
+from pylib.utils import isolator
 
 
 def CreateTestInstance(args, error_func):
 
   if args.command == 'gtest':
     return gtest_test_instance.GtestTestInstance(
-        args, isolator.Isolator(constants.ISOLATE_DEPS_DIR), error_func)
+        args, isolator.Isolator(), error_func)
   elif args.command == 'instrumentation':
     return instrumentation_test_instance.InstrumentationTestInstance(
-        args, isolator.Isolator(constants.ISOLATE_DEPS_DIR), error_func)
+        args, isolator.Isolator(), error_func)
   elif args.command == 'uirobot':
     return uirobot_test_instance.UirobotTestInstance(args, error_func)
 
diff --git a/build/android/pylib/base/test_run_factory.py b/build/android/pylib/base/test_run_factory.py
index 8c71ebb..72b22bc 100644
--- a/build/android/pylib/base/test_run_factory.py
+++ b/build/android/pylib/base/test_run_factory.py
@@ -3,9 +3,9 @@
 # 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_gtest_run
 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
diff --git a/build/android/pylib/chrome_test_server_spawner.py b/build/android/pylib/chrome_test_server_spawner.py
index 052c2fd..a77a0c9 100644
--- a/build/android/pylib/chrome_test_server_spawner.py
+++ b/build/android/pylib/chrome_test_server_spawner.py
@@ -21,9 +21,9 @@
 import time
 import urlparse
 
-from pylib import constants
-from pylib import ports
+from devil.android import ports
 
+from pylib import constants
 from pylib.forwarder import Forwarder
 
 
@@ -224,11 +224,18 @@
       command = [os.path.join(command, 'net', 'tools', 'testserver',
                               'testserver.py')] + self.command_line
     logging.info('Running: %s', command)
+
+    # Disable PYTHONUNBUFFERED because it has a bad interaction with the
+    # testserver. Remove once this interaction is fixed.
+    unbuf = os.environ.pop('PYTHONUNBUFFERED', None)
+
     # 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 unbuf:
+      os.environ['PYTHONUNBUFFERED'] = unbuf
     if self.process:
       if self.pipe_out:
         self.is_ready = self._WaitToStartAndGetPortFromTestServer()
diff --git a/build/android/pylib/cmd_helper.py b/build/android/pylib/cmd_helper.py
index f881553..2d1b1b3 100644
--- a/build/android/pylib/cmd_helper.py
+++ b/build/android/pylib/cmd_helper.py
@@ -1,261 +1,8 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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."""
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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)
+from devil.utils.cmd_helper import *
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py
index cb5f899..772af93 100644
--- a/build/android/pylib/constants/__init__.py
+++ b/build/android/pylib/constants/__init__.py
@@ -13,15 +13,16 @@
 import os
 import subprocess
 
+import devil.android.sdk.keyevent
+from devil.android.sdk import version_codes
+from devil.constants import exit_codes
+
+keyevent = devil.android.sdk.keyevent
+
 
 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',
@@ -70,6 +71,12 @@
         '/data/local/chrome-command-line',
         'chrome_devtools_remote',
         None),
+    'chromium': PackageInfo(
+        'org.chromium.chrome',
+        'com.google.android.apps.chrome.Main',
+        '/data/local/chrome-command-line',
+        'chrome_devtools_remote',
+        'org.chromium.chrome.tests'),
     'legacy_browser': PackageInfo(
         'com.google.android.browser',
         'com.android.browser.BrowserActivity',
@@ -88,12 +95,6 @@
         '/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',
@@ -102,7 +103,7 @@
         'org.chromium.android_webview.test'),
     'gtest': PackageInfo(
         'org.chromium.native_test',
-        'org.chromium.native_test.NativeTestActivity',
+        'org.chromium.native_test.NativeUnitTestActivity',
         '/data/local/tmp/chrome-native-tests-command-line',
         None,
         None),
@@ -110,13 +111,13 @@
         'org.chromium.components_browsertests_apk',
         ('org.chromium.components_browsertests_apk' +
          '.ComponentsBrowserTestsActivity'),
-        '/data/local/tmp/components-browser-tests-command-line',
+        '/data/local/tmp/chrome-native-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',
+        '/data/local/tmp/chrome-native-tests-command-line',
         None,
         None),
     'chromedriver_webview_shell': PackageInfo(
@@ -138,14 +139,6 @@
 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.
@@ -163,32 +156,19 @@
 
 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
-  """
-
-  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_VERSION = version_codes.MARSHMALLOW
+ANDROID_SDK_BUILD_TOOLS_VERSION = '23.0.1'
 ANDROID_SDK_ROOT = os.path.join(DIR_SOURCE_ROOT,
-                                'third_party/android_tools/sdk')
+                                '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')
+                                'third_party', 'android_tools', 'ndk')
 
-EMULATOR_SDK_ROOT = os.environ.get('ANDROID_EMULATOR_SDK_ROOT',
-                                   os.path.join(DIR_SOURCE_ROOT,
-                                                'android_emulator_sdk'))
+PROGUARD_SCRIPT_PATH = os.path.join(
+    ANDROID_SDK_ROOT, 'tools', 'proguard', 'bin', 'proguard.sh')
+
+PROGUARD_ROOT = os.path.join(DIR_SOURCE_ROOT, 'third_party', 'proguard')
 
 BAD_DEVICES_JSON = os.path.join(DIR_SOURCE_ROOT,
                                 os.environ.get('CHROMIUM_OUT_DIR', 'out'),
@@ -196,22 +176,26 @@
 
 UPSTREAM_FLAKINESS_SERVER = 'test-results.appspot.com'
 
+# TODO(jbudorick): Remove once unused.
 DEVICE_LOCAL_PROPERTIES_PATH = '/data/local.prop'
 
+# TODO(jbudorick): Rework this into testing/buildbot/
 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',
+      'devil.android.device_utils_test',
+      'devil.android.md5sum_test',
+      'devil.utils.cmd_helper_test',
       'pylib.results.json_results_test',
-      'pylib.utils.md5sum_test',
+      'pylib.utils.proguard_test',
     ]
   },
   'gyp_py_unittests': {
     'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android', 'gyp'),
     'test_modules': [
       'java_cpp_enum_tests',
+      'java_google_api_keys_tests',
     ]
   },
 }
@@ -219,7 +203,7 @@
 LOCAL_MACHINE_TESTS = ['junit', 'python']
 VALID_ENVIRONMENTS = ['local', 'remote_device']
 VALID_TEST_TYPES = ['gtest', 'instrumentation', 'junit', 'linker', 'monkey',
-                    'perf', 'python', 'uiautomator', 'uirobot']
+                    'perf', 'python', 'uirobot']
 VALID_DEVICE_TYPES = ['Android', 'iOS']
 
 
@@ -297,6 +281,6 @@
     return os.path.join(ANDROID_SDK_ROOT, 'platform-tools', 'adb')
 
 # Exit codes
-ERROR_EXIT_CODE = 1
-INFRA_EXIT_CODE = 87
-WARNING_EXIT_CODE = 88
+ERROR_EXIT_CODE = exit_codes.ERROR
+INFRA_EXIT_CODE = exit_codes.INFRA
+WARNING_EXIT_CODE = exit_codes.WARNING
diff --git a/build/android/pylib/content_settings.py b/build/android/pylib/content_settings.py
index 8594140..3bf11bc 100644
--- a/build/android/pylib/content_settings.py
+++ b/build/android/pylib/content_settings.py
@@ -2,8 +2,6 @@
 # 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):
 
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index f88eab3..f66619f 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -1,606 +1,8 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. 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.
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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 InstallMultiple(self, apk_paths, forward_lock=False, reinstall=False,
-                      sd_card=False, allow_downgrade=False, partial=False,
-                      timeout=60*2, retries=_DEFAULT_RETRIES):
-    """Install an apk with splits on the device.
-
-    Args:
-      apk_paths: 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.
-      allow_downgrade: (optional) Allow versionCode downgrade.
-      partial: (optional) Package ID if apk_paths doesn't include all .apks.
-    """
-    for path in apk_paths:
-      _VerifyLocalFileExists(path)
-    cmd = ['install-multiple']
-    if forward_lock:
-      cmd.append('-l')
-    if reinstall:
-      cmd.append('-r')
-    if sd_card:
-      cmd.append('-s')
-    if allow_downgrade:
-      cmd.append('-d')
-    if partial:
-      cmd.extend(('-p', partial))
-    cmd.extend(apk_paths)
-    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
+from devil.android.sdk.adb_wrapper import *
diff --git a/build/android/pylib/device/battery_utils.py b/build/android/pylib/device/battery_utils.py
index ed66591..95c5613 100644
--- a/build/android/pylib/device/battery_utils.py
+++ b/build/android/pylib/device/battery_utils.py
@@ -2,404 +2,7 @@
 # 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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)
+from devil.android.battery_utils import *
diff --git a/build/android/pylib/device/battery_utils_test.py b/build/android/pylib/device/battery_utils_test.py
deleted file mode 100755
index 72799b8..0000000
--- a/build/android/pylib/device/battery_utils_test.py
+++ /dev/null
@@ -1,328 +0,0 @@
-#!/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
index 66e1010..c6d4b42 100644
--- a/build/android/pylib/device/commands/BUILD.gn
+++ b/build/android/pylib/device/commands/BUILD.gn
@@ -5,7 +5,7 @@
 import("//build/config/android/rules.gni")
 
 group("commands") {
-  datadeps = [
+  data_deps = [
     ":chromium_commands",
   ]
 }
diff --git a/build/android/pylib/device/commands/install_commands.py b/build/android/pylib/device/commands/install_commands.py
index 58c56cc..fde606f 100644
--- a/build/android/pylib/device/commands/install_commands.py
+++ b/build/android/pylib/device/commands/install_commands.py
@@ -3,7 +3,9 @@
 # found in the LICENSE file.
 
 import os
+import posixpath
 
+from devil.android import device_errors
 from pylib import constants
 
 BIN_DIR = '%s/bin' % constants.TEST_EXECUTABLE_DIR
@@ -22,19 +24,24 @@
 
 
 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))
+  paths = [posixpath.join(BIN_DIR, c) for c in _COMMANDS]
+  paths.append(posixpath.join(_FRAMEWORK_DIR, 'chromium_commands.jar'))
+  return device.PathExists(paths)
+
 
 def InstallCommands(device):
   if device.IsUserBuild():
-    raise Exception('chromium_commands currently requires a userdebug build.')
+    raise device_errors.CommandFailedError(
+        'chromium_commands currently requires a userdebug build.',
+        device_serial=device.adb.GetDeviceSerial())
 
   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)
+    raise device_errors.CommandFailedError(
+        '%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():
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
index 4d2a045..7cbbb73 100644
--- 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
@@ -38,6 +38,7 @@
         s.println("unzip [zipfile]");
     }
 
+    @SuppressWarnings("Finally")
     private void unzip(String[] args) {
         ZipInputStream zis = null;
         try {
diff --git a/build/android/pylib/device/decorators.py b/build/android/pylib/device/decorators.py
index 73c13da..f8c2fdd 100644
--- a/build/android/pylib/device/decorators.py
+++ b/build/android/pylib/device/decorators.py
@@ -1,157 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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.
-"""
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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
-
+from devil.android.decorators import *
diff --git a/build/android/pylib/device/device_blacklist.py b/build/android/pylib/device/device_blacklist.py
index a141d62..fad1ca6 100644
--- a/build/android/pylib/device/device_blacklist.py
+++ b/build/android/pylib/device/device_blacklist.py
@@ -1,61 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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)
-
+from devil.android.device_blacklist import *
diff --git a/build/android/pylib/device/device_errors.py b/build/android/pylib/device/device_errors.py
index 2492015..cb09c3c 100644
--- a/build/android/pylib/device/device_errors.py
+++ b/build/android/pylib/device/device_errors.py
@@ -1,89 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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.
-"""
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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)
+from devil.android.device_errors import *
diff --git a/build/android/pylib/device/device_list.py b/build/android/pylib/device/device_list.py
index 0eb6acb..a730277 100644
--- a/build/android/pylib/device/device_list.py
+++ b/build/android/pylib/device/device_list.py
@@ -1,30 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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."""
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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)))
+from devil.android.device_list import *
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index 967809f..b8e8de2 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -1,1588 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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.
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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 the pylib.constants.keyevent module for suitable keycode values.
-
-    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)
-
-  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)]
-
+from devil.android.device_utils import *
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
deleted file mode 100755
index 23a1a32..0000000
--- a/build/android/pylib/device/device_utils_test.py
+++ /dev/null
@@ -1,1682 +0,0 @@
-#!/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)
-
-
-@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
index 333b9f1..cb6fb68 100644
--- a/build/android/pylib/device/intent.py
+++ b/build/android/pylib/device/intent.py
@@ -1,113 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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.
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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
+from devil.android.sdk.intent import *
diff --git a/build/android/pylib/device/logcat_monitor.py b/build/android/pylib/device/logcat_monitor.py
index 2eebc2d..0e492cb 100644
--- a/build/android/pylib/device/logcat_monitor.py
+++ b/build/android/pylib/device/logcat_monitor.py
@@ -2,138 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# pylint: disable=unused-argument
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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
+from devil.android.logcat_monitor import *
diff --git a/build/android/pylib/device/shared_prefs.py b/build/android/pylib/device/shared_prefs.py
index 32cef4b..38db76a 100644
--- a/build/android/pylib/device/shared_prefs.py
+++ b/build/android/pylib/device/shared_prefs.py
@@ -2,390 +2,7 @@
 # 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.
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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)
+from devil.android.sdk.shared_prefs import *
diff --git a/build/android/pylib/device_settings.py b/build/android/pylib/device_settings.py
index 97e9663..1147c02 100644
--- a/build/android/pylib/device_settings.py
+++ b/build/android/pylib/device_settings.py
@@ -4,14 +4,13 @@
 
 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'
+_COMPATIBLE_BUILD_TYPES = ['userdebug', 'eng']
 
 
 def ConfigureContentSettings(device, desired_settings):
@@ -29,7 +28,7 @@
     desired_settings: A list of (table, [(key: value), ...]) for all
         settings to configure.
   """
-  if device.build_type == 'userdebug':
+  if device.build_type in _COMPATIBLE_BUILD_TYPES:
     for table, key_value in desired_settings:
       settings = content_settings.ContentSettings(table, device)
       for key, value in key_value:
@@ -58,8 +57,9 @@
   Raises:
     Exception if the setting was not properly set.
   """
-  if device.build_type != 'userdebug':
-    logging.warning('Unable to disable lockscreen on user builds.')
+  if device.build_type not in _COMPATIBLE_BUILD_TYPES:
+    logging.warning('Unable to disable lockscreen on %s builds.',
+                    device.build_type)
     return
 
   def get_lock_settings(table):
@@ -127,6 +127,18 @@
   ]),
 ]
 
+ENABLE_MOCK_LOCATION_SETTINGS = [
+  ('settings/secure', [
+    ('mock_location', 1),
+  ]),
+]
+
+DISABLE_MOCK_LOCATION_SETTINGS = [
+  ('settings/secure', [
+    ('mock_location', 0),
+  ]),
+]
+
 DETERMINISTIC_DEVICE_SETTINGS = [
   ('settings/global', [
     ('assisted_gps_enabled', 0),
diff --git a/build/android/pylib/device_signal.py b/build/android/pylib/device_signal.py
index 6a5b709..ca57690 100644
--- a/build/android/pylib/device_signal.py
+++ b/build/android/pylib/device_signal.py
@@ -2,40 +2,7 @@
 # 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.
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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
+from devil.android.device_signal import *
diff --git a/build/android/pylib/flag_changer.py b/build/android/pylib/flag_changer.py
index 718bc39..5b9021f 100644
--- a/build/android/pylib/flag_changer.py
+++ b/build/android/pylib/flag_changer.py
@@ -4,18 +4,13 @@
 
 import logging
 
-import pylib.android_commands
-import pylib.device.device_utils
-
-from pylib.device import device_errors
+from devil.android 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
+    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.
   """
@@ -27,83 +22,97 @@
       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 = ''
+    stored_flags = ''
+    if self._device.PathExists(self._cmdline_file):
+      try:
+        stored_flags = self._device.ReadFile(self._cmdline_file).strip()
+      except device_errors.CommandFailedError:
+        pass
+    # Store the flags as a set to facilitate adding and removing flags.
+    self._state_stack = [set(self._TokenizeFlags(stored_flags))]
 
-    # 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.
+  def ReplaceFlags(self, flags):
+    """Replaces the flags in the command line with the ones provided.
+       Saves the current flags state on the stack, so a call to Restore will
+       change the state back to the one preceeding the call to ReplaceFlags.
 
     Args:
-      flags: A list of flags to set, eg. ['--single-process'].
+      flags: A sequence of command line flags to set, eg. ['--single-process'].
+             Note: this should include flags only, not the name of a command
+             to run (ie. there is no need to start the sequence with 'chrome').
     """
-    if flags:
-      assert flags[0] != 'chrome'
-
-    self._current_flags = flags
+    new_flags = set(flags)
+    self._state_stack.append(new_flags)
     self._UpdateCommandLineFile()
 
   def AddFlags(self, flags):
     """Appends flags to the command line if they aren't already there.
+       Saves the current flags state on the stack, so a call to Restore will
+       change the state back to the one preceeding the call to AddFlags.
 
     Args:
-      flags: A list of flags to add on, eg. ['--single-process'].
+      flags: A sequence 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()
+    self.PushFlags(add=flags)
 
   def RemoveFlags(self, flags):
     """Removes flags from the command line, if they exist.
+       Saves the current flags state on the stack, so a call to Restore will
+       change the state back to the one preceeding the call to RemoveFlags.
+
+       Note that calling RemoveFlags after AddFlags will result in having
+       two nested states.
 
     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.
+      flags: A sequence 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'
+    self.PushFlags(remove=flags)
 
-    for flag in flags:
-      if flag in self._current_flags:
-        self._current_flags.remove(flag)
-    self._UpdateCommandLineFile()
+  def PushFlags(self, add=None, remove=None):
+    """Appends and removes flags to/from the command line if they aren't already
+       there. Saves the current flags state on the stack, so a call to Restore
+       will change the state back to the one preceeding the call to PushFlags.
+
+    Args:
+      add: A list of flags to add on, eg. ['--single-process'].
+      remove: 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.
+    """
+    new_flags = self._state_stack[-1].copy()
+    if add:
+      new_flags.update(add)
+    if remove:
+      new_flags.difference_update(remove)
+    self.ReplaceFlags(new_flags)
 
   def Restore(self):
-    """Restores the flags to their original state."""
-    self._current_flags = self._TokenizeFlags(self._orig_line)
+    """Restores the flags to their state prior to the last AddFlags or
+       RemoveFlags call.
+    """
+    # The initial state must always remain on the stack.
+    assert len(self._state_stack) > 1, (
+      "Mismatch between calls to Add/RemoveFlags and Restore")
+    self._state_stack.pop()
     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)
+    current_flags = list(self._state_stack[-1])
+    logging.info('Current flags: %s', 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:
+    if 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)
+      cmd_line = ' '.join(['_'] + current_flags)
       self._device.WriteFile(
           self._cmdline_file, cmd_line, as_root=use_root)
       file_contents = self._device.ReadFile(
diff --git a/build/android/pylib/forwarder.py b/build/android/pylib/forwarder.py
index d16b9b1..36226d1 100644
--- a/build/android/pylib/forwarder.py
+++ b/build/android/pylib/forwarder.py
@@ -9,13 +9,9 @@
 import os
 import psutil
 
-from pylib import cmd_helper
+from devil.android.valgrind_tools import base_tool
+from devil.utils 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):
@@ -73,11 +69,8 @@
     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)
+      tool = base_tool.BaseTool()
     with _FileLock(Forwarder._LOCK_PATH):
       instance = Forwarder._GetInstanceLocked(tool)
       instance._InitDeviceLocked(device, tool)
@@ -101,6 +94,12 @@
           else: raise
         if exit_code != 0:
           Forwarder._KillDeviceLocked(device, tool)
+          # Log alive forwarders
+          ps_out = device.RunShellCommand(['ps'])
+          logging.info('Currently running device_forwarders:')
+          for line in ps_out:
+            if 'device_forwarder' in line:
+              logging.info('    %s', line)
           raise Exception('%s exited with %d:\n%s' % (
               instance._host_forwarder_path, exit_code, '\n'.join(output)))
         tokens = output.split(':')
@@ -123,9 +122,6 @@
       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)
 
@@ -137,9 +133,6 @@
       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
@@ -152,14 +145,14 @@
         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)
+      tool = base_tool.BaseTool()
       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(
+      _, device_port = Forwarder._GetInstanceLocked(
           None)._host_to_device_port_map.get(host_port)
       return device_port
 
@@ -221,16 +214,18 @@
     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)
+      logging.error('Trying to unmap non-forwarded port %d', device_port)
       return
     redirection_command = ['--adb=' + constants.GetAdbPath(),
                            '--serial-id=' + serial,
                            '--unmap', str(device_port)]
+    logging.info('Undo forwarding using command: %s', redirection_command)
     (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)))
+      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]
@@ -289,7 +284,8 @@
         Forwarder._DEVICE_FORWARDER_FOLDER)])
     cmd = '%s %s' % (tool.GetUtilWrapper(), Forwarder._DEVICE_FORWARDER_PATH)
     device.RunShellCommand(
-        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER})
+        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER},
+        check_return=True)
     self._initialized_devices.add(device_serial)
 
   def _KillHostLocked(self):
@@ -326,4 +322,5 @@
     cmd = '%s %s --kill-server' % (tool.GetUtilWrapper(),
                                    Forwarder._DEVICE_FORWARDER_PATH)
     device.RunShellCommand(
-        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER})
+        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER},
+        check_return=True)
diff --git a/build/android/pylib/gtest/filter/blink_heap_unittests_disabled b/build/android/pylib/gtest/filter/blink_heap_unittests_disabled
deleted file mode 100644
index 7a43fb1..0000000
--- a/build/android/pylib/gtest/filter/blink_heap_unittests_disabled
+++ /dev/null
@@ -1,2 +0,0 @@
-# List of suppressions
-
diff --git a/build/android/pylib/gtest/filter/cc_unittests_disabled b/build/android/pylib/gtest/filter/cc_unittests_disabled
deleted file mode 100644
index feab5ac..0000000
--- a/build/android/pylib/gtest/filter/cc_unittests_disabled
+++ /dev/null
@@ -1,5 +0,0 @@
-# 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
index 39eff4d..b9dd105 100644
--- a/build/android/pylib/gtest/filter/content_browsertests_disabled
+++ b/build/android/pylib/gtest/filter/content_browsertests_disabled
@@ -34,6 +34,7 @@
 RendererAccessibilityTest.SendFullAccessibilityTreeOnReload
 RendererAccessibilityTest.HideAccessibilityObject
 RendererAccessibilityTest.ShowAccessibilityObject
+RendererAccessibilityTest.TextSelectionShouldSendRoot
 
 # http://crbug.com/215894
 DownloadContentTest.CancelInterruptedDownload
@@ -49,9 +50,6 @@
 # http://crbug.com/386227
 IndexedDBBrowserTest.VersionChangeCrashResilience
 
-# http://crbug.com/386222
-IndexedDBBrowserTest.DoesntHangTest
-
 # http://crbug.com/233118
 IndexedDBBrowserTest.NullKeyPathPersistence
 
diff --git a/build/android/pylib/gtest/filter/content_unittests_disabled b/build/android/pylib/gtest/filter/content_unittests_disabled
deleted file mode 100644
index 925a7d1..0000000
--- a/build/android/pylib/gtest/filter/content_unittests_disabled
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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
deleted file mode 100644
index ade8b38..0000000
--- a/build/android/pylib/gtest/filter/gfx_unittests_disabled
+++ /dev/null
@@ -1,27 +0,0 @@
-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
deleted file mode 100644
index e8d0691..0000000
--- a/build/android/pylib/gtest/filter/ipc_tests_disabled
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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
deleted file mode 100644
index ed3b9aa..0000000
--- a/build/android/pylib/gtest/filter/media_unittests_disabled
+++ /dev/null
@@ -1,8 +0,0 @@
-# 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
deleted file mode 100644
index 75a1c86..0000000
--- a/build/android/pylib/gtest/filter/net_unittests_disabled
+++ /dev/null
@@ -1,41 +0,0 @@
-# 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
deleted file mode 100644
index cc4b72d..0000000
--- a/build/android/pylib/gtest/filter/sync_unit_tests_disabled
+++ /dev/null
@@ -1,4 +0,0 @@
-SyncHttpBridgeTest.*
-
-# crbug.com/144422
-OnDiskSyncableDirectory.FailInitialWrite
diff --git a/build/android/pylib/gtest/filter/webkit_unit_tests_disabled b/build/android/pylib/gtest/filter/webkit_unit_tests_disabled
index 50292aa..1ffa325 100644
--- a/build/android/pylib/gtest/filter/webkit_unit_tests_disabled
+++ b/build/android/pylib/gtest/filter/webkit_unit_tests_disabled
@@ -23,6 +23,3 @@
 
 # crbug.com/320005
 CoreAnimationCompositorAnimationsTest.ConvertTimingForCompositorIterationCount
-
-# crbug.com/412145
-TouchActionTest.Pan
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
index b6f83b3..4250ea3 100644
--- a/build/android/pylib/gtest/gtest_test_instance.py
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -5,16 +5,48 @@
 import logging
 import os
 import re
-import shutil
 import sys
+import tempfile
 
+from devil.android import apk_helper
 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
+import unittest_util # pylint: disable=import-error
+
+
+BROWSER_TEST_SUITES = [
+  'components_browsertests',
+  'content_browsertests',
+]
+
+RUN_IN_SUB_THREAD_TEST_SUITES = ['net_unittests']
+
+
+_DEFAULT_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
@@ -40,6 +72,18 @@
 ]
 
 
+_EXTRA_NATIVE_TEST_ACTIVITY = (
+    'org.chromium.native_test.NativeTestInstrumentationTestRunner.'
+        'NativeTestActivity')
+_EXTRA_RUN_IN_SUB_THREAD = (
+    'org.chromium.native_test.NativeTestActivity.RunInSubThread')
+EXTRA_SHARD_NANO_TIMEOUT = (
+    'org.chromium.native_test.NativeTestInstrumentationTestRunner.'
+        'ShardNanoTimeout')
+_EXTRA_SHARD_SIZE_LIMIT = (
+    'org.chromium.native_test.NativeTestInstrumentationTestRunner.'
+        'ShardSizeLimit')
+
 # TODO(jbudorick): Remove these once we're no longer parsing stdout to generate
 # results.
 _RE_TEST_STATUS = re.compile(
@@ -92,23 +136,31 @@
       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._shard_timeout = args.shard_timeout
+
+    incremental_part = '_incremental' if args.incremental_install else ''
+    apk_path = os.path.join(
+        constants.GetOutDirectory(), '%s_apk' % self._suite,
+        '%s-debug%s.apk' % (self._suite, incremental_part))
     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(apk_path):
+      self._apk_helper = None
+    else:
+      self._apk_helper = apk_helper.ApkHelper(apk_path)
+      self._extras = {
+          _EXTRA_NATIVE_TEST_ACTIVITY: self._apk_helper.GetActivityName(),
+      }
+      if self._suite in RUN_IN_SUB_THREAD_TEST_SUITES:
+        self._extras[_EXTRA_RUN_IN_SUB_THREAD] = 1
+      if self._suite in BROWSER_TEST_SUITES:
+        self._extras[_EXTRA_SHARD_SIZE_LIMIT] = 1
+        self._extras[EXTRA_SHARD_NANO_TIMEOUT] = int(1e9 * self._shard_timeout)
+        self._shard_timeout = 900
+
     if not os.path.exists(self._exe_path):
       self._exe_path = None
-    if not self._apk_path and not self._exe_path:
+    if not self._apk_helper and not self._exe_path:
       error_func('Could not find apk or executable for %s' % self._suite)
 
     self._data_deps = []
@@ -119,15 +171,91 @@
         self._gtest_filter = ':'.join(l.strip() for l in f)
     else:
       self._gtest_filter = None
+
+    if not args.isolate_file_path:
+      default_isolate_file_path = _DEFAULT_ISOLATE_FILE_PATHS.get(self._suite)
+      if default_isolate_file_path:
+        args.isolate_file_path = os.path.join(
+            constants.DIR_SOURCE_ROOT, default_isolate_file_path)
+
     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.');
+      logging.warning('No isolate file provided. No data deps will be pushed.')
       self._isolate_delegate = None
 
+    if args.app_data_files:
+      self._app_data_files = args.app_data_files
+      if args.app_data_file_dir:
+        self._app_data_file_dir = args.app_data_file_dir
+      else:
+        self._app_data_file_dir = tempfile.mkdtemp()
+        logging.critical('Saving app files to %s', self._app_data_file_dir)
+    else:
+      self._app_data_files = None
+      self._app_data_file_dir = None
+
+    self._test_arguments = args.test_arguments
+
+  @property
+  def activity(self):
+    return self._apk_helper and self._apk_helper.GetActivityName()
+
+  @property
+  def apk(self):
+    return self._apk_helper and self._apk_helper.path
+
+  @property
+  def apk_helper(self):
+    return self._apk_helper
+
+  @property
+  def app_file_dir(self):
+    return self._app_data_file_dir
+
+  @property
+  def app_files(self):
+    return self._app_data_files
+
+  @property
+  def exe(self):
+    return self._exe_path
+
+  @property
+  def extras(self):
+    return self._extras
+
+  @property
+  def gtest_filter(self):
+    return self._gtest_filter
+
+  @property
+  def package(self):
+    return self._apk_helper and self._apk_helper.GetPackageName()
+
+  @property
+  def permissions(self):
+    return self._apk_helper and self._apk_helper.GetPermissions()
+
+  @property
+  def runner(self):
+    return self._apk_helper and self._apk_helper.GetInstrumentationName()
+
+  @property
+  def shard_timeout(self):
+    return self._shard_timeout
+
+  @property
+  def suite(self):
+    return self._suite
+
+  @property
+  def test_arguments(self):
+    return self._test_arguments
+
   #override
   def TestType(self):
     return 'gtest'
@@ -143,7 +271,8 @@
       dest_dir = None
       if self._suite == 'breakpad_unittests':
         dest_dir = '/data/local/tmp/'
-      self._data_deps.extend([(constants.ISOLATE_DEPS_DIR, dest_dir)])
+      self._data_deps.extend([
+          (self._isolate_delegate.isolate_deps_dir, dest_dir)])
 
 
   def GetDataDependencies(self):
@@ -196,6 +325,7 @@
 
     return '*-%s' % ':'.join(disabled_filter_items)
 
+  # pylint: disable=no-self-use
   def ParseGTestOutput(self, output):
     """Parses raw gtest output and returns a list of results.
 
@@ -204,22 +334,32 @@
     Returns:
       A list of base_test_result.BaseTestResults.
     """
+    log = []
+    result_type = None
     results = []
     for l in output:
+      logging.info(l)
       matcher = _RE_TEST_STATUS.match(l)
       if matcher:
-        result_type = None
-        if matcher.group(1) == 'OK':
+        if matcher.group(1) == 'RUN':
+          log = []
+        elif 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)
+      if log is not None:
+        log.append(l)
+
+      if result_type:
+        test_name = matcher.group(2)
+        duration = int(matcher.group(3)) if matcher.group(3) else 0
+        results.append(base_test_result.BaseTestResult(
+            test_name, result_type, duration,
+            log=('\n'.join(log) if log else '')))
+        log = None
+        result_type = None
+
     return results
 
   #override
@@ -228,15 +368,3 @@
     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/local_device_gtest_run.py b/build/android/pylib/gtest/local_device_gtest_run.py
deleted file mode 100644
index 4241e85..0000000
--- a/build/android/pylib/gtest/local_device_gtest_run.py
+++ /dev/null
@@ -1,206 +0,0 @@
-# Copyright 2014 The Chromium 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
deleted file mode 100644
index d51b90e..0000000
--- a/build/android/pylib/gtest/setup.py
+++ /dev/null
@@ -1,249 +0,0 @@
-# Copyright 2013 The Chromium 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)
-
-  i = 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)
-  if i:
-    i.Clear()
-
-  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
deleted file mode 100644
index 58cd82b..0000000
--- a/build/android/pylib/gtest/test_options.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2013 The Chromium 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
deleted file mode 100644
index dbd47bf..0000000
--- a/build/android/pylib/gtest/test_package.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (c) 2012 The Chromium 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
deleted file mode 100644
index 9672f7a..0000000
--- a/build/android/pylib/gtest/test_package_apk.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# Copyright (c) 2012 The Chromium 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
deleted file mode 100644
index 7cdcb99..0000000
--- a/build/android/pylib/gtest/test_package_exe.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# Copyright (c) 2012 The Chromium 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 = []
-    if self.tool.GetTestWrapper():
-      cmd.append(self.tool.GetTestWrapper())
-    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
deleted file mode 100644
index 4926388..0000000
--- a/build/android/pylib/gtest/test_runner.py
+++ /dev/null
@@ -1,201 +0,0 @@
-# Copyright (c) 2012 The Chromium 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/test_case.py b/build/android/pylib/host_driven/test_case.py
index 6ff4c5f..2c552f7 100644
--- a/build/android/pylib/host_driven/test_case.py
+++ b/build/android/pylib/host_driven/test_case.py
@@ -28,7 +28,6 @@
 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
@@ -155,7 +154,8 @@
     start_ms = int(time.time()) * 1000
     done = False
     for test_filter in test_filters:
-      tests = test_pkg.GetAllMatchingTests(None, None, test_filter)
+      tests = test_pkg.GetAllMatchingTests(
+          None, None, test_filter, [self.device])
       # Filters should always result in >= 1 test.
       if len(tests) == 0:
         raise Exception('Java test filter "%s" returned no tests.'
diff --git a/build/android/pylib/host_driven/test_runner.py b/build/android/pylib/host_driven/test_runner.py
index 8620aa1..678c08e 100644
--- a/build/android/pylib/host_driven/test_runner.py
+++ b/build/android/pylib/host_driven/test_runner.py
@@ -87,7 +87,7 @@
 
     try:
       test.SetUp(self.device, self.shard_index)
-    except Exception:
+    except Exception: # pylint: disable=broad-except
       logging.exception(
           'Caught exception while trying to run SetUp() for test: ' +
           test.tagged_name)
@@ -101,7 +101,7 @@
 
     try:
       results = test.Run()
-    except Exception:
+    except Exception: # pylint: disable=broad-except
       # Setting this lets TearDown() avoid stomping on our stack trace from
       # Run() should TearDown() also raise an exception.
       exception_raised = True
@@ -114,7 +114,7 @@
 
     try:
       test.TearDown()
-    except Exception:
+    except Exception: # pylint: disable=broad-except
       logging.exception(
           'Caught exception while trying run TearDown() for test: ' +
           test.tagged_name)
diff --git a/build/android/pylib/host_driven/test_server.py b/build/android/pylib/host_driven/test_server.py
index 0783500..af58ddc 100644
--- a/build/android/pylib/host_driven/test_server.py
+++ b/build/android/pylib/host_driven/test_server.py
@@ -117,11 +117,11 @@
     while retries < 5:
       try:
         d = urllib2.urlopen(test_url).read()
-        logging.info('URL %s GOT: %s' % (test_url, d))
+        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))
+      except Exception as e: # pylint: disable=broad-except
+        logging.info('URL %s GOT: %s', test_url, e)
       time.sleep(retries * 0.1)
       retries += 1
 
diff --git a/build/android/pylib/instrumentation/instrumentation_parser.py b/build/android/pylib/instrumentation/instrumentation_parser.py
index 1859f14..efd5efb 100644
--- a/build/android/pylib/instrumentation/instrumentation_parser.py
+++ b/build/android/pylib/instrumentation/instrumentation_parser.py
@@ -15,7 +15,7 @@
 RESULT_CODE_OK = -1
 RESULT_CODE_CANCELED = 0
 
-_INSTR_LINE_RE = re.compile('^\s*INSTRUMENTATION_([A-Z_]+): (.*)$')
+_INSTR_LINE_RE = re.compile(r'^\s*INSTRUMENTATION_([A-Z_]+): (.*)$')
 
 
 class InstrumentationParser(object):
@@ -38,7 +38,7 @@
 
     Args:
       stream: a sequence of lines as produced by the raw output of an
-        instrumentation test (e.g. by |am instrument -r| or |uiautomator|).
+        instrumentation test (e.g. by |am instrument -r|).
     """
     self._stream = stream
     self._code = None
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index 0633f14..4536f6e 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -2,34 +2,37 @@
 # 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 logging
 import os
 import pickle
 import re
 import sys
 
-from pylib import cmd_helper
+from devil.android import apk_helper
+from devil.android import md5sum
 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
+import unittest_util # pylint: disable=import-error
 
 # Ref: http://developer.android.com/reference/android/app/Activity.html
 _ACTIVITY_RESULT_CANCELED = 0
 _ACTIVITY_RESULT_OK = -1
 
+_COMMAND_LINE_PARAMETER = 'cmdlinearg-parameter'
 _DEFAULT_ANNOTATIONS = [
     'Smoke', 'SmallTest', 'MediumTest', 'LargeTest',
     'EnormousTest', 'IntegrationTest']
+_EXCLUDE_UNLESS_REQUESTED_ANNOTATIONS = [
+    'DisabledTest', 'FlakyTest']
 _EXTRA_ENABLE_HTTP_SERVER = (
     'org.chromium.chrome.test.ChromeInstrumentationTestRunner.'
         + 'EnableTestHttpServer')
@@ -41,6 +44,8 @@
     'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage')
 _EXTRA_DRIVER_TARGET_CLASS = (
     'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass')
+_PARAMETERIZED_TEST_ANNOTATION = 'ParameterizedTest'
+_PARAMETERIZED_TEST_SET_ANNOTATION = 'ParameterizedTest$Set'
 _NATIVE_CRASH_RE = re.compile('native crash', re.IGNORECASE)
 _PICKLE_FORMAT_VERSION = 10
 
@@ -134,17 +139,70 @@
   return results
 
 
+def ParseCommandLineFlagParameters(annotations):
+  """Determines whether the test is parameterized to be run with different
+     command-line flags.
+
+  Args:
+    annotations: The annotations of the test.
+
+  Returns:
+    If the test is parameterized, returns a list of named tuples
+    with lists of flags, e.g.:
+
+      [(add=['--flag-to-add']), (remove=['--flag-to-remove']), ()]
+
+    That means, the test must be run three times, the first time with
+    "--flag-to-add" added to command-line, the second time with
+    "--flag-to-remove" to be removed from command-line, and the third time
+    with default command-line args. If the same flag is listed both for adding
+    and for removing, it is left unchanged.
+
+    If the test is not parametrized, returns None.
+
+  """
+  ParamsTuple = collections.namedtuple('ParamsTuple', ['add', 'remove'])
+  parameterized_tests = []
+  if _PARAMETERIZED_TEST_SET_ANNOTATION in annotations:
+    if annotations[_PARAMETERIZED_TEST_SET_ANNOTATION]:
+      parameterized_tests = annotations[
+        _PARAMETERIZED_TEST_SET_ANNOTATION].get('tests', [])
+  elif _PARAMETERIZED_TEST_ANNOTATION in annotations:
+    parameterized_tests = [annotations[_PARAMETERIZED_TEST_ANNOTATION]]
+  else:
+    return None
+
+  result = []
+  for pt in parameterized_tests:
+    if not pt:
+      continue
+    for p in pt['parameters']:
+      if p['tag'] == _COMMAND_LINE_PARAMETER:
+        to_add = []
+        to_remove = []
+        for a in p.get('arguments', []):
+          if a['name'] == 'add':
+            to_add = ['--%s' % f for f in a['stringArray']]
+          elif a['name'] == 'remove':
+            to_remove = ['--%s' % f for f in a['stringArray']]
+        result.append(ParamsTuple(to_add, to_remove))
+  return result if result else None
+
+
 class InstrumentationTestInstance(test_instance.TestInstance):
 
   def __init__(self, args, isolate_delegate, error_func):
     super(InstrumentationTestInstance, self).__init__()
 
+    self._additional_apks = []
     self._apk_under_test = None
+    self._apk_under_test_permissions = None
     self._package_info = None
     self._suite = None
     self._test_apk = None
     self._test_jar = None
     self._test_package = None
+    self._test_permissions = None
     self._test_runner = None
     self._test_support_apk = None
     self._initializeApkAttributes(args, error_func)
@@ -169,6 +227,9 @@
     self._driver_name = None
     self._initializeDriverAttributes()
 
+    self._timeout_scale = None
+    self._initializeTestControlAttributes(args)
+
   def _initializeApkAttributes(self, args, error_func):
     if args.apk_under_test.endswith('.apk'):
       self._apk_under_test = args.apk_under_test
@@ -180,6 +241,9 @@
     if not os.path.exists(self._apk_under_test):
       error_func('Unable to find APK under test: %s' % self._apk_under_test)
 
+    apk = apk_helper.ApkHelper(self._apk_under_test)
+    self._apk_under_test_permissions = apk.GetPermissions()
+
     if args.test_apk.endswith('.apk'):
       self._suite = os.path.splitext(os.path.basename(args.test_apk))[0]
       self._test_apk = args.test_apk
@@ -201,8 +265,10 @@
     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)
+    apk = apk_helper.ApkHelper(self.test_apk)
+    self._test_package = apk.GetPackageName()
+    self._test_permissions = apk.GetPermissions()
+    self._test_runner = apk.GetInstrumentationName()
 
     self._package_info = None
     for package_info in constants.PACKAGE_INFO.itervalues():
@@ -211,6 +277,11 @@
     if not self._package_info:
       logging.warning('Unable to find package info for %s', self._test_package)
 
+    for apk in args.additional_apks:
+      if not os.path.exists(apk):
+        error_func('Unable to find additional APK: %s' % apk)
+    self._additional_apks = args.additional_apks
+
   def _initializeDataDependencyAttributes(self, args, isolate_delegate):
     self._data_deps = []
     if args.isolate_file_path:
@@ -257,6 +328,12 @@
     else:
       self._excluded_annotations = {}
 
+    self._excluded_annotations.update(
+        {
+          a: None for a in _EXCLUDE_UNLESS_REQUESTED_ANNOTATIONS
+          if a not in self._annotations
+        })
+
   def _initializeFlagAttributes(self, args):
     self._flags = ['--disable-fre', '--enable-test-intents']
     # TODO(jbudorick): Transition "--device-flags" to "--device-flags-file"
@@ -274,18 +351,28 @@
         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)
+      driver_apk = apk_helper.ApkHelper(self._driver_apk)
+      self._driver_package = driver_apk.GetPackageName()
+      self._driver_name = driver_apk.GetInstrumentationName()
     else:
       self._driver_apk = None
 
+  def _initializeTestControlAttributes(self, args):
+    self._timeout_scale = args.timeout_scale or 1
+
+  @property
+  def additional_apks(self):
+    return self._additional_apks
+
   @property
   def apk_under_test(self):
     return self._apk_under_test
 
   @property
+  def apk_under_test_permissions(self):
+   return self._apk_under_test_permissions
+
+  @property
   def flags(self):
     return self._flags
 
@@ -326,9 +413,17 @@
     return self._test_package
 
   @property
+  def test_permissions(self):
+    return self._test_permissions
+
+  @property
   def test_runner(self):
     return self._test_runner
 
+  @property
+  def timeout_scale(self):
+    return self._timeout_scale
+
   #override
   def TestType(self):
     return 'instrumentation'
@@ -339,7 +434,7 @@
       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)])
+      self._data_deps.extend([(self._isolate_delegate.isolate_deps_dir, None)])
 
     # TODO(jbudorick): Convert existing tests that depend on the --test-data
     # mechanism to isolate, then remove this.
@@ -359,10 +454,11 @@
     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))
+      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))
+    return self._ParametrizeTestsWithFlags(
+        self._InflateTests(self._FilterTests(tests)))
 
   class ProguardPickleException(Exception):
     pass
@@ -388,6 +484,7 @@
       logging.error(pickle_data)
       raise self.ProguardPickleException(str(e))
 
+  # pylint: disable=no-self-use
   def _GetTestsFromProguard(self, jar_path):
     p = proguard.Dump(jar_path)
 
@@ -486,6 +583,18 @@
         })
     return inflated_tests
 
+  def _ParametrizeTestsWithFlags(self, tests):
+    new_tests = []
+    for t in tests:
+      parameters = ParseCommandLineFlagParameters(t['annotations'])
+      if parameters:
+        t['flags'] = parameters[0]
+        for p in parameters[1:]:
+          parameterized_t = copy.copy(t)
+          parameterized_t['flags'] = p
+          new_tests.append(parameterized_t)
+    return tests + new_tests
+
   @staticmethod
   def GetHttpServerEnvironmentVars():
     return {
diff --git a/build/android/pylib/instrumentation/json_perf_parser.py b/build/android/pylib/instrumentation/json_perf_parser.py
index ffdfbe7..c647890 100644
--- a/build/android/pylib/instrumentation/json_perf_parser.py
+++ b/build/android/pylib/instrumentation/json_perf_parser.py
@@ -65,7 +65,7 @@
 
   def EntryFilter(entry):
     return entry['cat'] == 'Java' and entry['name'] == name
-  filtered_entries = filter(EntryFilter, json_data)
+  filtered_entries = [j for j in json_data if EntryFilter(j)]
 
   result = {}
 
diff --git a/build/android/pylib/instrumentation/setup.py b/build/android/pylib/instrumentation/setup.py
index 7a0501e..ceaab04 100644
--- a/build/android/pylib/instrumentation/setup.py
+++ b/build/android/pylib/instrumentation/setup.py
@@ -7,11 +7,10 @@
 import logging
 import os
 
+from devil.android import device_utils
 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
 
@@ -19,7 +18,6 @@
 
 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',
 }
 
@@ -33,7 +31,8 @@
   Args:
     test_apk: The test suite basename for which to return file paths.
   """
-  if test_apk in ['ChromeTest', 'ContentShellTest']:
+  if test_apk in ['ChromeTest', 'ContentShellTest',
+                  'CronetTestInstrumentation']:
     test_files = 'net/data/ssl/certificates'
     host_device_file_tuple = [
         (os.path.join(constants.DIR_SOURCE_ROOT, test_files),
@@ -82,7 +81,8 @@
   tests = test_pkg.GetAllMatchingTests(
       test_options.annotations,
       test_options.exclude_annotations,
-      test_options.test_filter)
+      test_options.test_filter,
+      devices)
   if not tests:
     logging.error('No instrumentation tests to run with current args.')
 
@@ -91,17 +91,16 @@
         _PushDataDeps, test_options)
 
   if test_options.isolate_file_path:
-    i = base_setup.GenerateDepsDirUsingIsolate(test_options.test_apk,
-                                           test_options.isolate_file_path,
-                                           ISOLATE_FILE_PATHS,
-                                           DEPS_EXCLUSION_LIST)
+    isolator = 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)
+      base_setup.PushDataDeps(device, isolator.isolate_deps_dir,
+                              device.GetExternalStoragePath(), test_options)
     device_utils.DeviceUtils.parallel(devices).pMap(
         push_data_deps_to_device_dir)
-    if i:
-      i.Clear()
+    if isolator:
+      isolator.Clear()
 
   device_utils.DeviceUtils.parallel(devices).pMap(
       _PushExtraSuiteDataDeps, test_options.test_apk)
diff --git a/build/android/pylib/instrumentation/test_jar.py b/build/android/pylib/instrumentation/test_jar.py
index 9c38510..1ae653c 100644
--- a/build/android/pylib/instrumentation/test_jar.py
+++ b/build/android/pylib/instrumentation/test_jar.py
@@ -11,10 +11,9 @@
 import re
 import sys
 
-from pylib import cmd_helper
+from devil.android import device_utils
+from devil.android import md5sum
 from pylib import constants
-from pylib.device import device_utils
-from pylib.utils import md5sum
 from pylib.utils import proguard
 
 sys.path.insert(0,
@@ -32,6 +31,8 @@
       ['Smoke', 'SmallTest', 'MediumTest', 'LargeTest', 'EnormousTest',
        'FlakyTest', 'DisabledTest', 'Manual', 'PerfTest', 'HostDrivenTest',
        'IntegrationTest'])
+  _EXCLUDE_UNLESS_REQUESTED_ANNOTATIONS = frozenset(
+      ['DisabledTest', 'FlakyTest'])
   _DEFAULT_ANNOTATION = 'SmallTest'
   _PROGUARD_CLASS_RE = re.compile(r'\s*?- Program class:\s*([\S]+)$')
   _PROGUARD_SUPERCLASS_RE = re.compile(r'\s*?  Superclass:\s*([\S]+)$')
@@ -45,8 +46,8 @@
     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')
+    self._PROGUARD_PATH = os.path.join(constants.PROGUARD_ROOT,
+                                       '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')
@@ -65,7 +66,8 @@
       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]
+        jar_md5 = md5sum.CalculateHostMd5Sums(
+          self._jar_path)[os.path.realpath(self._jar_path)]
         if (d['JAR_MD5SUM'] == jar_md5 and
             d['VERSION'] == PICKLE_FORMAT_VERSION):
           self._test_methods = d['TEST_METHODS']
@@ -106,7 +108,8 @@
     d = {'VERSION': PICKLE_FORMAT_VERSION,
          'TEST_METHODS': self._test_methods,
          'JAR_MD5SUM':
-              md5sum.CalculateHostMd5Sums(self._jar_path)[self._jar_path]}
+              md5sum.CalculateHostMd5Sums(
+                self._jar_path)[os.path.realpath(self._jar_path)]}
     with open(self._pickled_proguard_name, 'w') as f:
       f.write(pickle.dumps(d))
 
@@ -118,7 +121,7 @@
   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 {}
     return self._test_methods[test]['annotations']
 
   @staticmethod
@@ -132,8 +135,11 @@
         key = filters[0]
         value_list = filters[1].split(',')
         for value in value_list:
-          if key in annotations and value == annotations[key]:
-            return True
+          if key in annotations and annotations[key]['value']:
+            annotation_value = annotations[key]['value']
+            if ((isinstance(annotation_value, list) and
+                 value in annotation_value) or value == annotation_value):
+              return True
       elif annotation_filter in annotations:
         return True
     return False
@@ -162,13 +168,15 @@
     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))
+    required_min_sdk_level = self.GetTestAnnotations(
+      test_name).get('MinAndroidSdkLevel', None)
+    if required_min_sdk_level:
+      required_min_sdk_level = int(required_min_sdk_level['value'])
     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):
+                          exclude_annotation_list, test_filter, devices):
     """Get a list of tests matching any of the annotations and the filter.
 
     Args:
@@ -178,6 +186,7 @@
       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.
+      devices: The set of devices against which tests will be run.
 
     Returns:
       List of all matching tests.
@@ -195,9 +204,14 @@
       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))
+    requested_annotations = set(annotation_filter_list or ())
+    exclude_annotation_list = list(exclude_annotation_list or ())
+
+    exclude_annotation_list.extend([
+        a for a in self._EXCLUDE_UNLESS_REQUESTED_ANNOTATIONS
+        if a not in requested_annotations])
+    excluded_tests = self.GetAnnotatedTests(exclude_annotation_list)
+    available_tests = list(set(available_tests) - set(excluded_tests))
 
     tests = []
     if test_filter:
@@ -216,7 +230,7 @@
 
     # Filter out any tests with SDK level requirements that don't match the set
     # of attached devices.
-    devices = device_utils.DeviceUtils.parallel()
+    devices = device_utils.DeviceUtils.parallel(devices)
     min_sdk_version = min(devices.build_version_sdk.pGet(None))
     tests = [t for t in tests
              if self._IsTestValidForSdkRange(t, min_sdk_version)]
diff --git a/build/android/pylib/instrumentation/test_options.py b/build/android/pylib/instrumentation/test_options.py
index 792010b..b5276b7 100644
--- a/build/android/pylib/instrumentation/test_options.py
+++ b/build/android/pylib/instrumentation/test_options.py
@@ -23,4 +23,6 @@
     'test_support_apk_path',
     'device_flags',
     'isolate_file_path',
-    'set_asserts'])
+    'set_asserts',
+    'delete_stale_data',
+    'timeout_scale'])
diff --git a/build/android/pylib/instrumentation/test_package.py b/build/android/pylib/instrumentation/test_package.py
index f32556f..1f56b5e 100644
--- a/build/android/pylib/instrumentation/test_package.py
+++ b/build/android/pylib/instrumentation/test_package.py
@@ -6,8 +6,8 @@
 
 import os
 
+from devil.android import apk_helper
 from pylib.instrumentation import test_jar
-from pylib.utils import apk_helper
 
 
 class TestPackage(test_jar.TestJar):
@@ -39,4 +39,3 @@
     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_runner.py b/build/android/pylib/instrumentation/test_runner.py
index d1c5a4d..7ff1ed6 100644
--- a/build/android/pylib/instrumentation/test_runner.py
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -4,18 +4,19 @@
 
 """Class for running instrumentation tests on a single device."""
 
+import collections
 import logging
 import os
 import re
 import sys
 import time
 
+from devil.android import device_errors
 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
@@ -56,13 +57,17 @@
     self.coverage_dir = test_options.coverage_dir
     self.coverage_host_file = None
     self.options = test_options
+    package_info_candidates = [a for a in constants.PACKAGE_INFO.itervalues()
+                               if a.test_package == test_pkg.GetPackageName()]
+    assert len(package_info_candidates) < 2, (
+        'Multiple packages have the same test package')
+    self.package_info = (package_info_candidates[0] if package_info_candidates
+                         else None)
     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 self.package_info and self.package_info.cmdline_file:
+      self.flags = flag_changer.FlagChanger(
+          self.device, self.package_info.cmdline_file)
       if additional_flags:
         self.flags.AddFlags(additional_flags)
     else:
@@ -96,10 +101,9 @@
                       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')
+        self.device.WaitUntilFullyBooted()
 
     # 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
@@ -107,11 +111,12 @@
     self.LaunchTestHttpServer(
         os.path.join(constants.DIR_SOURCE_ROOT), self._lighttp_port)
     if self.flags:
-      self.flags.AddFlags(['--disable-fre', '--enable-test-intents'])
+      flags_to_add = ['--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])
+          flags_to_add.extend([flag for flag in stripped_flags if flag])
+      self.flags.AddFlags(flags_to_add)
 
   def TearDown(self):
     """Cleans up the test harness and saves outstanding data from test run."""
@@ -119,7 +124,7 @@
       self.flags.Restore()
     super(TestRunner, self).TearDown()
 
-  def TestSetup(self, test):
+  def TestSetup(self, test, flag_modifiers):
     """Sets up the test harness for running a particular test.
 
     Args:
@@ -129,8 +134,8 @@
     self._SetupIndividualTestTimeoutScale(test)
     self.tool.SetupEnvironment()
 
-    if self.flags and self._IsFreTest(test):
-      self.flags.RemoveFlags(['--disable-fre'])
+    if self.flags:
+      self.flags.PushFlags(add=flag_modifiers.add, remove=flag_modifiers.remove)
 
     # Make sure the forwarder is still running.
     self._RestartHttpServerForwarderIfNecessary()
@@ -153,7 +158,8 @@
       Whether the feature being tested is FirstRunExperience.
     """
     annotations = self.test_pkg.GetTestAnnotations(test)
-    return 'FirstRunExperience' == annotations.get('Feature', None)
+    feature = annotations.get('Feature', None)
+    return feature and 'FirstRunExperience' in feature['value']
 
   def _IsPerfTest(self, test):
     """Determines whether a test is a performance test.
@@ -166,6 +172,23 @@
     """
     return _PERF_TEST_ANNOTATION in self.test_pkg.GetTestAnnotations(test)
 
+  def _GetTestCmdlineParameters(self, test):
+    """Determines whether the test is parameterized to be run with different
+       command-line flags.
+
+    Args:
+      test: The name of the test to be checked.
+
+    Returns:
+      The list of parameters.
+    """
+    annotations = self.test_pkg.GetTestAnnotations(test)
+    params = instrumentation_test_instance.ParseCommandLineFlagParameters(
+      annotations)
+    if not params:
+      params = [collections.namedtuple('Dummy', ['add', 'remove'])([], [])]
+    return params
+
   def SetupPerfMonitoringIfNeeded(self, test):
     """Sets up performance monitoring if the specified test requires it.
 
@@ -179,7 +202,7 @@
     self._logcat_monitor = self.device.GetLogcatMonitor()
     self._logcat_monitor.Start()
 
-  def TestTeardown(self, test, result):
+  def TestTeardown(self, test, results):
     """Cleans up the test harness after running a particular test.
 
     Depending on the options of this TestRunner this might handle performance
@@ -187,25 +210,26 @@
 
     Args:
       test: The name of the test that was just run.
-      result: result for this test.
+      results: results for this test.
     """
 
     self.tool.CleanUpEnvironment()
 
-    # The logic below relies on the test passing.
-    if not result or not result.DidRunPass():
+    if self.flags:
+      self.flags.Restore()
+
+    if not results:
       return
+    if results.DidRunPass():
+      self.TearDownPerfMonitoring(test)
 
-    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)
+      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)
+    elif self.package_info:
+      self.device.ClearApplicationState(self.package_info.package)
 
   def TearDownPerfMonitoring(self, test):
     """Cleans up performance monitoring if the specified test required it.
@@ -264,7 +288,8 @@
                                                     result['units'])
 
   def _SetupIndividualTestTimeoutScale(self, test):
-    timeout_scale = self._GetIndividualTestTimeoutScale(test)
+    timeout_scale = self.options.timeout_scale or 1
+    timeout_scale *= self._GetIndividualTestTimeoutScale(test)
     valgrind_tools.SetChromeTimeoutScale(self.device, timeout_scale)
 
   def _GetIndividualTestTimeoutScale(self, test):
@@ -273,14 +298,15 @@
     timeout_scale = 1
     if 'TimeoutScale' in annotations:
       try:
-        timeout_scale = int(annotations['TimeoutScale'])
+        timeout_scale = int(annotations['TimeoutScale']['value'])
       except ValueError:
-        logging.warning('Non-integer value of TimeoutScale ignored. (%s)'
-                        % annotations['TimeoutScale'])
+        logging.warning('Non-integer value of TimeoutScale ignored. (%s)',
+                        annotations['TimeoutScale']['value'])
     if self.options.wait_for_debugger:
       timeout_scale *= 100
     return timeout_scale
 
+  # pylint: disable=too-many-return-statements
   def _GetIndividualTestTimeoutSecs(self, test):
     """Returns the timeout in seconds for the given |test|."""
     annotations = self.test_pkg.GetTestAnnotations(test)
@@ -299,8 +325,8 @@
     if 'SmallTest' in annotations:
       return 1 * 60
 
-    logging.warn(("Test size not found in annotations for test '%s', using " +
-                  "1 minute for timeout.") % test)
+    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):
@@ -317,8 +343,9 @@
     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)
+        raw=True, extras=extras, timeout=timeout, retries=0)
 
+  # pylint: disable=no-self-use
   def _GenerateTestResult(self, test, instr_result_code, instr_result_bundle,
                           statuses, start_ms, duration_ms):
     results = instrumentation_test_instance.GenerateTestResults(
@@ -337,32 +364,57 @@
                self._GetIndividualTestTimeoutScale(test) *
                self.tool.GetTimeoutScale())
 
-    start_ms = 0
-    duration_ms = 0
-    try:
-      self.TestSetup(test)
+    cmdline_parameters = self._GetTestCmdlineParameters(test)
+    for flag_modifiers in cmdline_parameters:
+      start_ms = 0
+      duration_ms = 0
+      try:
+        if self._IsFreTest(test):
+          flag_modifiers.remove.append('--disable-fre')
+        self.TestSetup(test, flag_modifiers)
 
-      time_ms = lambda: int(time.time() * 1000)
-      start_ms = time_ms()
-      raw_output = self._RunTest(test, timeout)
-      duration_ms = time_ms() - start_ms
+        try:
+          self.device.GoHome()
+        except device_errors.CommandTimeoutError:
+          logging.exception('Failed to focus the launcher.')
 
-      # 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(
+        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)
+      except device_errors.CommandTimeoutError as e:
+        result = 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)
+          log=str(e) or 'No information')
+        if self.package_info:
+          self.device.ForceStop(self.package_info.package)
+          self.device.ForceStop(self.package_info.test_package)
+      except device_errors.DeviceUnreachableError as e:
+        result = test_result.InstrumentationTestResult(
+            test, base_test_result.ResultType.CRASH, start_ms, duration_ms,
+            log=str(e) or 'No information')
+      if len(cmdline_parameters) > 1:
+        # Specify commandline flag modifications used in the test run
+        result_name = result.GetName()
+        if flag_modifiers.add:
+          result_name = '%s with {%s}' % (
+            result_name, ' '.join(flag_modifiers.add))
+        if flag_modifiers.remove:
+          result_name = '%s without {%s}' % (
+            result_name, ' '.join(flag_modifiers.remove))
+        result.SetName(result_name)
+      results.AddResult(result)
+
+      self.TestTeardown(test, results)
+
     return (results, None if results.DidRunPass() else test)
diff --git a/build/android/pylib/junit/test_dispatcher.py b/build/android/pylib/junit/test_dispatcher.py
index 6e0d865..51253d4 100644
--- a/build/android/pylib/junit/test_dispatcher.py
+++ b/build/android/pylib/junit/test_dispatcher.py
@@ -25,4 +25,5 @@
     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
+  return (test_run_results, exit_code)
+
diff --git a/build/android/pylib/junit/test_runner.py b/build/android/pylib/junit/test_runner.py
index a6d3bf9..dea8cdc 100644
--- a/build/android/pylib/junit/test_runner.py
+++ b/build/android/pylib/junit/test_runner.py
@@ -6,9 +6,8 @@
 import os
 import tempfile
 
-from pylib import cmd_helper
+from devil.utils import cmd_helper
 from pylib import constants
-from pylib.base import base_test_result
 from pylib.results import json_results
 
 class JavaTestRunner(object):
diff --git a/build/android/pylib/linker/setup.py b/build/android/pylib/linker/setup.py
index 5776f5a..e561957 100644
--- a/build/android/pylib/linker/setup.py
+++ b/build/android/pylib/linker/setup.py
@@ -4,6 +4,7 @@
 
 """Setup for linker tests."""
 
+import logging
 import os
 import sys
 
@@ -16,21 +17,39 @@
                              'common'))
 import unittest_util # pylint: disable=F0401
 
-def Setup(args, _devices):
+# ModernLinker requires Android M (API level 23) or later.
+_VERSION_SDK_PROPERTY = 'ro.build.version.sdk'
+_MODERN_LINKER_MINIMUM_SDK_INT = 23
+
+def Setup(args, devices):
   """Creates a list of test cases and a runner factory.
 
   Args:
     args: an argparse.Namespace object.
+    devices: an iterable of available devices.
   Returns:
     A tuple of (TestRunnerFactory, tests).
   """
-  test_cases = [
-      test_case.LinkerLibraryAddressTest,
-      test_case.LinkerSharedRelroTest,
-      test_case.LinkerRandomizationTest]
+  legacy_linker_tests = [
+      test_case.LinkerSharedRelroTest(is_modern_linker=False,
+                                      is_low_memory=False),
+      test_case.LinkerSharedRelroTest(is_modern_linker=False,
+                                      is_low_memory=True),
+  ]
+  modern_linker_tests = [
+      test_case.LinkerSharedRelroTest(is_modern_linker=True),
+  ]
 
-  low_memory_modes = [False, True]
-  all_tests = [t(is_low_memory=m) for t in test_cases for m in low_memory_modes]
+  min_sdk_int = 1 << 31
+  for device in devices:
+    min_sdk_int = min(min_sdk_int, device.build_version_sdk)
+
+  if min_sdk_int >= _MODERN_LINKER_MINIMUM_SDK_INT:
+    all_tests = legacy_linker_tests + modern_linker_tests
+  else:
+    all_tests = legacy_linker_tests
+    logging.warn('Not running LinkerModern tests (requires API %d, found %d)',
+                 _MODERN_LINKER_MINIMUM_SDK_INT, min_sdk_int)
 
   if args.test_filter:
     all_test_names = [test.qualified_name for test in all_tests]
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py
index c7b0f50..475b730 100644
--- a/build/android/pylib/linker/test_case.py
+++ b/build/android/pylib/linker/test_case.py
@@ -36,14 +36,11 @@
 # pylint: disable=R0201
 
 import logging
-import os
 import re
-import time
 
-from pylib import constants
+from devil.android import device_errors
+from devil.android.sdk import intent
 from pylib.base import base_test_result
-from pylib.device import device_errors
-from pylib.device import intent
 
 
 ResultType = base_test_result.ResultType
@@ -52,65 +49,18 @@
 _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']
+# it is handy to have others as well when troubleshooting.
+_LOGCAT_FILTERS = ['*:s', 'chromium:v', 'cr_chromium:v',
+                   'cr_ChromiumAndroidLinker:v', 'cr_LibraryLoader:v',
+                   'cr_LinkerTest: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|.
@@ -168,85 +118,25 @@
     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):
+  def __init__(self, is_modern_linker=False, is_low_memory=False):
     """Create a test case.
     Args:
+      is_modern_linker: True to test ModernLinker, False to test LegacyLinker.
       is_low_memory: True to simulate a low-memory device, False otherwise.
     """
+    self.is_modern_linker = is_modern_linker
+    if is_modern_linker:
+      test_suffix = 'ForModernLinker'
+    else:
+      test_suffix = 'ForLegacyLinker'
     self.is_low_memory = is_low_memory
     if is_low_memory:
-      test_suffix = 'ForLowMemoryDevice'
+      test_suffix += 'LowMemoryDevice'
     else:
-      test_suffix = 'ForRegularDevice'
+      test_suffix += 'RegularDevice'
     class_name = self.__class__.__name__
     self.qualified_name = '%s.%s' % (class_name, test_suffix)
     self.tagged_name = self.qualified_name
@@ -274,9 +164,12 @@
     logging.info('Running linker test: %s', self.tagged_name)
 
     # Create command-line file on device.
-    command_line_flags = ''
+    if self.is_modern_linker:
+      command_line_flags = '--use-linker=modern'
+    else:
+      command_line_flags = '--use-linker=legacy'
     if self.is_low_memory:
-      command_line_flags = '--low-memory-device'
+      command_line_flags += ' --low-memory-device'
     device.WriteFile(_COMMAND_LINE_FILE, command_line_flags)
 
     # Run the test.
@@ -332,165 +225,3 @@
   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
index b6803e4..d345952 100644
--- a/build/android/pylib/linker/test_runner.py
+++ b/build/android/pylib/linker/test_runner.py
@@ -13,7 +13,6 @@
 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.
@@ -84,7 +83,7 @@
 
     try:
       results = test.Run(self.device)
-    except Exception:
+    except Exception: # pylint: disable=broad-except
       logging.exception('Caught exception while trying to run test: ' +
                         test.tagged_name)
       exc_info = sys.exc_info()
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py
index 0d02ca3..7d9651e 100644
--- a/build/android/pylib/local/device/local_device_environment.py
+++ b/build/android/pylib/local/device/local_device_environment.py
@@ -2,43 +2,80 @@
 # 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 threading
+
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.utils import parallelizer
+from pylib import constants
 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
+
+
+def _DeviceCachePath(device):
+  file_name = 'device_cache_%s.json' % device.adb.GetDeviceSerial()
+  return os.path.join(constants.GetOutDirectory(), file_name)
 
 
 class LocalDeviceEnvironment(environment.Environment):
 
   def __init__(self, args, _error_func):
     super(LocalDeviceEnvironment, self).__init__()
+    self._blacklist = (device_blacklist.Blacklist(args.blacklist_file)
+                       if args.blacklist_file
+                       else None)
     self._device_serial = args.test_device
+    self._devices_lock = threading.Lock()
     self._devices = []
     self._max_tries = 1 + args.num_retries
     self._tool_name = args.tool
+    self._enable_device_cache = args.enable_device_cache
+    self._incremental_install = args.incremental_install
+    self._concurrent_adb = args.enable_concurrent_adb
 
   #override
   def SetUp(self):
-    available_devices = device_utils.DeviceUtils.HealthyDevices()
+    available_devices = device_utils.DeviceUtils.HealthyDevices(
+        self._blacklist, enable_device_files_cache=self._enable_device_cache)
     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 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
 
+    if self._enable_device_cache:
+      for d in self._devices:
+        cache_path = _DeviceCachePath(d)
+        if os.path.exists(cache_path):
+          logging.info('Using device cache: %s', cache_path)
+          with open(cache_path) as f:
+            d.LoadCacheData(f.read())
+          os.unlink(cache_path)
+
   @property
   def devices(self):
+    if not self._devices:
+      raise device_errors.NoDevicesError()
     return self._devices
 
   @property
+  def concurrent_adb(self):
+    return self._concurrent_adb
+
+  @property
+  def incremental_install(self):
+    return self._incremental_install
+
+  @property
   def parallel_devices(self):
-    return parallelizer.SyncParallelizer(self._devices)
+    return parallelizer.SyncParallelizer(self.devices)
 
   @property
   def max_tries(self):
@@ -50,5 +87,24 @@
 
   #override
   def TearDown(self):
-    pass
+    # Write the cache even when not using it so that it will be ready the first
+    # time that it is enabled. Writing it every time is also necessary so that
+    # an invalid cache can be flushed just by disabling it for one run.
+    for d in self._devices:
+      cache_path = _DeviceCachePath(d)
+      with open(cache_path, 'w') as f:
+        f.write(d.DumpCacheData())
+        logging.info('Wrote device cache: %s', cache_path)
+
+  def BlacklistDevice(self, device, reason='local_device_failure'):
+    if not self._blacklist:
+      logging.warning(
+          'Attempted to blacklist %s, but no blacklist was provided.',
+          str(device))
+      return
+
+    device_serial = device.adb.GetDeviceSerial()
+    self._blacklist.Extend([device_serial], reason=reason)
+    with self._devices_lock:
+      self._devices = [d for d in self._devices if str(d) != device_serial]
 
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py
new file mode 100644
index 0000000..5fe7b4b
--- /dev/null
+++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -0,0 +1,333 @@
+# Copyright 2014 The Chromium 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 imp
+import itertools
+import os
+import posixpath
+
+from devil.android import device_errors
+from devil.android import device_temp_file
+from devil.android import ports
+from devil.utils import reraiser_thread
+from incremental_install import installer
+from pylib import constants
+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
+
+_COMMAND_LINE_FLAGS_SUPPORTED = True
+
+_MAX_INLINE_FLAGS_LENGTH = 50  # Arbitrarily chosen.
+_EXTRA_COMMAND_LINE_FILE = (
+    'org.chromium.native_test.NativeTestActivity.CommandLineFile')
+_EXTRA_COMMAND_LINE_FLAGS = (
+    'org.chromium.native_test.NativeTestActivity.CommandLineFlags')
+_EXTRA_TEST_LIST = (
+    'org.chromium.native_test.NativeTestInstrumentationTestRunner'
+        '.TestList')
+_EXTRA_TEST = (
+    'org.chromium.native_test.NativeTestInstrumentationTestRunner'
+        '.Test')
+
+_MAX_SHARD_SIZE = 256
+_SECONDS_TO_NANOS = int(1e9)
+
+# The amount of time a test executable may run before it gets killed.
+_TEST_TIMEOUT_SECONDS = 30*60
+
+# 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'
+]
+
+# No-op context manager. If we used Python 3, we could change this to
+# contextlib.ExitStack()
+class _NullContextManager(object):
+  def __enter__(self):
+    pass
+  def __exit__(self, *args):
+    pass
+
+
+# TODO(jbudorick): Move this inside _ApkDelegate once TestPackageApk is gone.
+def PullAppFilesImpl(device, package, files, directory):
+  device_dir = device.GetApplicationDataDirectory(package)
+  host_dir = os.path.join(directory, str(device))
+  for f in files:
+    device_file = posixpath.join(device_dir, f)
+    host_file = os.path.join(host_dir, *f.split(posixpath.sep))
+    host_file_base, ext = os.path.splitext(host_file)
+    for i in itertools.count():
+      host_file = '%s_%d%s' % (host_file_base, i, ext)
+      if not os.path.exists(host_file):
+        break
+    device.PullFile(device_file, host_file)
+
+
+class _ApkDelegate(object):
+  def __init__(self, test_instance):
+    self._activity = test_instance.activity
+    self._apk_helper = test_instance.apk_helper
+    self._package = test_instance.package
+    self._runner = test_instance.runner
+    self._permissions = test_instance.permissions
+    self._suite = test_instance.suite
+    self._component = '%s/%s' % (self._package, self._runner)
+    self._extras = test_instance.extras
+
+  def Install(self, device, incremental=False):
+    if not incremental:
+      device.Install(self._apk_helper, reinstall=True,
+                     permissions=self._permissions)
+      return
+
+    installer_script = os.path.join(constants.GetOutDirectory(), 'bin',
+                                    'install_%s_apk_incremental' % self._suite)
+    try:
+      install_wrapper = imp.load_source('install_wrapper', installer_script)
+    except IOError:
+      raise Exception(('Incremental install script not found: %s\n'
+                       'Make sure to first build "%s_incremental"') %
+                      (installer_script, self._suite))
+    params = install_wrapper.GetInstallParameters()
+
+    installer.Install(device, self._apk_helper, split_globs=params['splits'],
+                      native_libs=params['native_libs'],
+                      dex_files=params['dex_files'])
+
+  def Run(self, test, device, flags=None, **kwargs):
+    extras = dict(self._extras)
+
+    if ('timeout' in kwargs
+        and gtest_test_instance.EXTRA_SHARD_NANO_TIMEOUT not in extras):
+      # Make sure the instrumentation doesn't kill the test before the
+      # scripts do. The provided timeout value is in seconds, but the
+      # instrumentation deals with nanoseconds because that's how Android
+      # handles time.
+      extras[gtest_test_instance.EXTRA_SHARD_NANO_TIMEOUT] = int(
+          kwargs['timeout'] * _SECONDS_TO_NANOS)
+
+    command_line_file = _NullContextManager()
+    if flags:
+      if len(flags) > _MAX_INLINE_FLAGS_LENGTH:
+        command_line_file = device_temp_file.DeviceTempFile(device.adb)
+        device.WriteFile(command_line_file.name, '_ %s' % flags)
+        extras[_EXTRA_COMMAND_LINE_FILE] = command_line_file.name
+      else:
+        extras[_EXTRA_COMMAND_LINE_FLAGS] = flags
+
+    test_list_file = _NullContextManager()
+    if test:
+      if len(test) > 1:
+        test_list_file = device_temp_file.DeviceTempFile(device.adb)
+        device.WriteFile(test_list_file.name, '\n'.join(test))
+        extras[_EXTRA_TEST_LIST] = test_list_file.name
+      else:
+        extras[_EXTRA_TEST] = test[0]
+
+    with command_line_file, test_list_file:
+      try:
+        return device.StartInstrumentation(
+            self._component, extras=extras, raw=False, **kwargs)
+      except Exception:
+        device.ForceStop(self._package)
+        raise
+
+  def PullAppFiles(self, device, files, directory):
+    PullAppFilesImpl(device, self._package, files, directory)
+
+  def Clear(self, device):
+    device.ClearApplicationState(self._package, permissions=self._permissions)
+
+
+class _ExeDelegate(object):
+  def __init__(self, tr, exe):
+    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, incremental=False):
+    assert not incremental
+    # 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 Run(self, test, device, flags=None, **kwargs):
+    tool = self._test_run.GetTool(device).GetTestWrapper()
+    if tool:
+      cmd = [tool]
+    else:
+      cmd = []
+    cmd.append(self._exe_device_path)
+
+    if test:
+      cmd.append('--gtest_filter=%s' % ':'.join(test))
+    if flags:
+      cmd.append(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
+
+    output = device.RunShellCommand(
+        cmd, cwd=cwd, env=env, check_return=True, large_output=True, **kwargs)
+    return output
+
+  def PullAppFiles(self, device, files, directory):
+    pass
+
+  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)
+    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):
+    @local_device_test_run.handle_shard_failures
+    def individual_device_set_up(dev):
+      def install_apk():
+        # Install test APK.
+        self._delegate.Install(dev, incremental=self._env.incremental_install)
+
+      def push_test_data():
+        # Push data dependencies.
+        external_storage = dev.GetExternalStoragePath()
+        data_deps = self._test_instance.GetDataDependencies()
+        host_device_tuples = [
+            (h, d if d is not None else external_storage)
+            for h, d in data_deps]
+        dev.PushChangedFiles(host_device_tuples)
+
+      def init_tool_and_start_servers():
+        tool = self.GetTool(dev)
+        tool.CopyFiles(dev)
+        tool.SetupEnvironment()
+
+        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, tool))
+
+        for s in self._servers[str(dev)]:
+          s.SetUp()
+
+      steps = (install_apk, push_test_data, init_tool_and_start_servers)
+      if self._env.concurrent_adb:
+        reraiser_thread.RunAsync(steps)
+      else:
+        for step in steps:
+          step()
+
+    self._env.parallel_devices.pMap(individual_device_set_up)
+
+  #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 shards
+
+  #override
+  def _GetTests(self):
+    # Even when there's only one device, it still makes sense to retrieve the
+    # test list so that tests can be split up and run in batches rather than all
+    # at once (since test output is not streamed).
+    @local_device_test_run.handle_shard_failures_with(
+        on_failure=self._env.BlacklistDevice)
+    def list_tests(dev):
+      tests = self._delegate.Run(
+          None, dev, flags='--gtest_list_tests', timeout=20)
+      tests = gtest_test_instance.ParseGTestListTests(tests)
+      tests = self._test_instance.FilterTests(tests)
+      return tests
+
+    # Query all devices in case one fails.
+    test_lists = self._env.parallel_devices.pMap(list_tests).pGet(None)
+    # TODO(agrieve): Make this fail rather than return an empty list when
+    #     all devices fail.
+    return list(sorted(set().union(*[set(tl) for tl in test_lists if tl])))
+
+  #override
+  def _RunTest(self, device, test):
+    # Run the test.
+    timeout = (self._test_instance.shard_timeout
+               * self.GetTool(device).GetTimeoutScale())
+    output = self._delegate.Run(
+        test, device, flags=self._test_instance.test_arguments,
+        timeout=timeout, retries=0)
+    for s in self._servers[str(device)]:
+      s.Reset()
+    if self._test_instance.app_files:
+      self._delegate.PullAppFiles(device, self._test_instance.app_files,
+                                  self._test_instance.app_file_dir)
+    # Clearing data when using incremental install wipes out cached optimized
+    # dex files (and shouldn't be necessary by tests anyways).
+    if not self._env.incremental_install:
+      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):
+    @local_device_test_run.handle_shard_failures
+    def individual_device_tear_down(dev):
+      for s in self._servers.get(str(dev), []):
+        s.TearDown()
+
+      tool = self.GetTool(dev)
+      tool.CleanUpEnvironment()
+
+    self._env.parallel_devices.pMap(individual_device_tear_down)
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
index e388fce..e4fccaa 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -6,11 +6,10 @@
 import re
 import time
 
+from devil.android import device_errors
 from pylib import flag_changer
+from pylib import valgrind_tools
 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
 
 
@@ -32,7 +31,7 @@
   # loop or we are failing to dismiss.
   try:
     for _ in xrange(10):
-      package = _DismissCrashDialog(device)
+      package = device.DismissCrashDialogIfNeeded()
       if not package:
         return False
       # Assume test package convention of ".test" suffix
@@ -47,22 +46,6 @@
     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):
@@ -82,8 +65,12 @@
         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)
+      dev.Install(self._test_instance.apk_under_test,
+                  permissions=self._test_instance.apk_under_test_permissions)
+      dev.Install(self._test_instance.test_apk,
+                  permissions=self._test_instance.test_permissions)
+      for apk in self._test_instance.additional_apks:
+        dev.Install(apk)
 
       external_storage = dev.GetExternalStoragePath()
       host_device_tuples = [
@@ -99,12 +86,14 @@
         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)
+          self._CreateFlagChangerIfNeeded(dev)
           logging.debug('Attempting to set flags: %r',
                         self._test_instance.flags)
           self._flag_changers[str(dev)].AddFlags(self._test_instance.flags)
 
+      valgrind_tools.SetChromeTimeoutScale(
+          dev, self._test_instance.timeout_scale)
+
     self._env.parallel_devices.pMap(
         individual_device_set_up,
         self._test_instance.GetDataDependencies())
@@ -114,8 +103,15 @@
       if str(dev) in self._flag_changers:
         self._flag_changers[str(dev)].Restore()
 
+      valgrind_tools.SetChromeTimeoutScale(dev, None)
+
     self._env.parallel_devices.pMap(individual_device_tear_down)
 
+  def _CreateFlagChangerIfNeeded(self, device):
+    if not str(device) in self._flag_changers:
+      self._flag_changers[str(device)] = flag_changer.FlagChanger(
+        device, self._test_instance.package_info.cmdline_file)
+
   #override
   def _CreateShards(self, tests):
     return tests
@@ -128,10 +124,21 @@
   def _GetTestName(self, test):
     return '%s#%s' % (test['class'], test['method'])
 
+  def _GetTestNameForDisplay(self, test):
+    display_name = self._GetTestName(test)
+    flags = test['flags']
+    if flags.add:
+      display_name = '%s with {%s}' % (display_name, ' '.join(flags.add))
+    if flags.remove:
+      display_name = '%s without {%s}' % (display_name, ' '.join(flags.remove))
+    return display_name
+
   #override
   def _RunTest(self, device, test):
     extras = self._test_instance.GetHttpServerEnvironmentVars()
 
+    flags = None
+    test_timeout_scale = None
     if isinstance(test, list):
       if not self._test_instance.driver_apk:
         raise Exception('driver_apk does not exist. '
@@ -145,6 +152,7 @@
       test_names, timeouts = zip(*(name_and_timeout(t) for t in test))
 
       test_name = ','.join(test_names)
+      test_display_name = test_name
       target = '%s/%s' % (
           self._test_instance.driver_package,
           self._test_instance.driver_name)
@@ -154,22 +162,45 @@
       timeout = sum(timeouts)
     else:
       test_name = self._GetTestName(test)
+      test_display_name = test_name
       target = '%s/%s' % (
           self._test_instance.test_package, self._test_instance.test_runner)
       extras['class'] = test_name
-      timeout = self._GetTimeoutFromAnnotations(test['annotations'], test_name)
+      if 'flags' in test:
+        flags = test['flags']
+        test_display_name = self._GetTestNameForDisplay(test)
+      timeout = self._GetTimeoutFromAnnotations(
+        test['annotations'], test_display_name)
 
-    logging.info('preparing to run %s: %s' % (test_name, test))
+      test_timeout_scale = self._GetTimeoutScaleFromAnnotations(
+          test['annotations'])
+      if test_timeout_scale and test_timeout_scale != 1:
+        valgrind_tools.SetChromeTimeoutScale(
+            device, test_timeout_scale * self._test_instance.timeout_scale)
 
-    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
+    logging.info('preparing to run %s: %s', test_display_name, test)
+
+    if flags:
+      self._CreateFlagChangerIfNeeded(device)
+      self._flag_changers[str(device)].PushFlags(
+        add=flags.add, remove=flags.remove)
+
+    try:
+      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
+    finally:
+      if flags:
+        self._flag_changers[str(device)].Restore()
+      if test_timeout_scale:
+        valgrind_tools.SetChromeTimeoutScale(
+            device, self._test_instance.timeout_scale)
 
     # TODO(jbudorick): Make instrumentation tests output a JSON so this
     # doesn't have to parse the output.
-    logging.debug('output from %s:', test_name)
+    logging.debug('output from %s:', test_display_name)
     for l in output:
       logging.debug('  %s', l)
 
@@ -177,31 +208,41 @@
         self._test_instance.ParseAmInstrumentRawOutput(output))
     results = self._test_instance.GenerateTestResults(
         result_code, result_bundle, statuses, start_ms, duration_ms)
+    if flags:
+      for r in results:
+        if r.GetName() == test_name:
+          r.SetName(test_display_name)
     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)
+    # TODO(jbudorick): ClearApplicationState on failure before switching
+    # instrumentation tests to platform mode.
     return results
 
   #override
   def _ShouldShard(self):
     return True
 
-  @staticmethod
-  def _GetTimeoutFromAnnotations(annotations, test_name):
+  @classmethod
+  def _GetTimeoutScaleFromAnnotations(cls, annotations):
+    try:
+      return int(annotations.get('TimeoutScale', 1))
+    except ValueError as e:
+      logging.warning("Non-integer value of TimeoutScale ignored. (%s)", str(e))
+      return 1
+
+  @classmethod
+  def _GetTimeoutFromAnnotations(cls, annotations, test_name):
     for k, v in TIMEOUT_ANNOTATIONS:
       if k in annotations:
         timeout = v
+        break
     else:
-      logging.warning('Using default 1 minute timeout for %s' % test_name)
+      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
+    timeout *= cls._GetTimeoutScaleFromAnnotations(annotations)
 
     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
index fa24eb1..2a93c68 100644
--- a/build/android/pylib/local/device/local_device_test_run.py
+++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -2,14 +2,57 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import fnmatch
+import functools
 import logging
 
+from devil.android import device_errors
 from pylib import valgrind_tools
 from pylib.base import base_test_result
 from pylib.base import test_run
 from pylib.base import test_collection
 
 
+def handle_shard_failures(f):
+  """A decorator that handles device failures for per-device functions.
+
+  Args:
+    f: the function being decorated. The function must take at least one
+      argument, and that argument must be the device.
+  """
+  return handle_shard_failures_with(None)(f)
+
+
+def handle_shard_failures_with(on_failure):
+  """A decorator that handles device failures for per-device functions.
+
+  This calls on_failure in the event of a failure.
+
+  Args:
+    f: the function being decorated. The function must take at least one
+      argument, and that argument must be the device.
+    on_failure: A binary function to call on failure.
+  """
+  def decorator(f):
+    @functools.wraps(f)
+    def wrapper(dev, *args, **kwargs):
+      try:
+        return f(dev, *args, **kwargs)
+      except device_errors.CommandFailedError:
+        logging.exception('Shard failed: %s(%s)', f.__name__, str(dev))
+      except device_errors.CommandTimeoutError:
+        logging.exception('Shard timed out: %s(%s)', f.__name__, str(dev))
+      except device_errors.DeviceUnreachableError:
+        logging.exception('Shard died: %s(%s)', f.__name__, str(dev))
+      if on_failure:
+        on_failure(dev, f.__name__)
+      return None
+
+    return wrapper
+
+  return decorator
+
+
 class LocalDeviceTestRun(test_run.TestRun):
 
   def __init__(self, env, test_instance):
@@ -20,46 +63,73 @@
   def RunTests(self):
     tests = self._GetTests()
 
-    def run_tests_on_device(dev, tests):
-      r = base_test_result.TestRunResults()
+    @handle_shard_failures
+    def run_tests_on_device(dev, tests, results):
       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
+        result = None
+        try:
+          result = self._RunTest(dev, test)
+          if isinstance(result, base_test_result.BaseTestResult):
+            results.AddResult(result)
+          elif isinstance(result, list):
+            results.AddResults(result)
+          else:
+            raise Exception(
+                'Unexpected result type: %s' % type(result).__name__)
+        except:
+          if isinstance(tests, test_collection.TestCollection):
+            tests.add(test)
+          raise
+        finally:
+          if isinstance(tests, test_collection.TestCollection):
+            tests.test_completed()
+
+
+      logging.info('Finished running tests on this device.')
 
     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))
+      logging.info('STARTING TRY #%d/%d', tries + 1, self._env.max_tries)
+      logging.info('Will run %d tests on %d devices: %s',
+                   len(tests), len(self._env.devices),
+                   ', '.join(str(d) for d in self._env.devices))
       for t in tests:
         logging.debug('  %s', t)
 
+      try_results = base_test_result.TestRunResults()
       if self._ShouldShard():
         tc = test_collection.TestCollection(self._CreateShards(tests))
-        try_results = self._env.parallel_devices.pMap(
-            run_tests_on_device, tc).pGet(None)
+        self._env.parallel_devices.pMap(
+            run_tests_on_device, tc, try_results).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
+        self._env.parallel_devices.pMap(
+            run_tests_on_device, tests, try_results).pGet(None)
+
+      for result in try_results.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]
+
+      def has_test_result(name):
+        # When specifying a test filter, names can contain trailing wildcards.
+        # See local_device_gtest_run._ExtractTestsFromFilter()
+        if name.endswith('*'):
+          return any(fnmatch.fnmatch(n, name) for n in results_names)
+        return name in results_names
+
+      tests = [t for t in tests if not has_test_result(self._GetTestName(t))]
       tries += 1
+      logging.info('FINISHED TRY #%d/%d', tries, self._env.max_tries)
+      if tests:
+        logging.info('%d failed tests remain.', len(tests))
+      else:
+        logging.info('All tests completed.')
 
     all_unknown_test_names = set(self._GetTestName(t) for t in tests)
     all_failed_test_names = set(all_fail_results.iterkeys())
@@ -86,6 +156,7 @@
   def _CreateShards(self, tests):
     raise NotImplementedError
 
+  # pylint: disable=no-self-use
   def _GetTestName(self, test):
     return test
 
diff --git a/build/android/pylib/monkey/test_runner.py b/build/android/pylib/monkey/test_runner.py
index 3fd1797..ff4c940 100644
--- a/build/android/pylib/monkey/test_runner.py
+++ b/build/android/pylib/monkey/test_runner.py
@@ -7,11 +7,11 @@
 import logging
 import random
 
+from devil.android import device_errors
+from devil.android.sdk import intent
 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
 
@@ -66,6 +66,10 @@
     # Run the test.
     output = ''
     if before_pids:
+      if len(before_pids.get(self._package, [])) > 1:
+        raise Exception(
+            'At most one instance of process %s expected but found pids: '
+            '%s' % (self._package, before_pids))
       output = '\n'.join(self._LaunchMonkeyTest())
       after_pids = self.device.GetPids(self._package)
 
diff --git a/build/android/pylib/perf/cache_control.py b/build/android/pylib/perf/cache_control.py
index 8065cf9..8b46575 100644
--- a/build/android/pylib/perf/cache_control.py
+++ b/build/android/pylib/perf/cache_control.py
@@ -1,21 +1,8 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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)
-
+from devil.android.perf.cache_control import *
diff --git a/build/android/pylib/perf/perf_control.py b/build/android/pylib/perf/perf_control.py
index f89f397..d95d7b7 100644
--- a/build/android/pylib/perf/perf_control.py
+++ b/build/android/pylib/perf/perf_control.py
@@ -1,161 +1,8 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-from pylib import android_commands
-from pylib.device import device_errors
-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."""
-    try:
-      self._device.EnableRoot()
-    except device_errors.CommandFailedError:
-      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"')
+from devil.android.perf.perf_control import *
diff --git a/build/android/pylib/perf/setup.py b/build/android/pylib/perf/setup.py
index 8e1fc28..dac7bae 100644
--- a/build/android/pylib/perf/setup.py
+++ b/build/android/pylib/perf/setup.py
@@ -10,15 +10,14 @@
 import os
 import shutil
 
+from devil.android import device_list
+from devil.android import device_utils
 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():
+def _GetAllDevices(active_devices):
   devices_path = os.path.join(os.environ.get('CHROMIUM_OUT_DIR', 'out'),
                               device_list.LAST_DEVICES_FILENAME)
   try:
@@ -26,7 +25,7 @@
                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()
+    devices = active_devices
   return sorted(devices)
 
 
@@ -56,7 +55,7 @@
       return steps
 
 
-def Setup(test_options):
+def Setup(test_options, active_devices):
   """Create and return the test runner factory and tests.
 
   Args:
@@ -72,10 +71,10 @@
   os.makedirs(constants.PERF_OUTPUT_DIR)
 
   # Before running the tests, kill any leftover server.
-  test_environment.CleanupLeftoverProcesses()
+  test_environment.CleanupLeftoverProcesses(active_devices)
 
   # We want to keep device affinity, so return all devices ever seen.
-  all_devices = _GetAllDevices()
+  all_devices = _GetAllDevices(active_devices)
 
   steps_dict = _GetStepsDict(test_options)
   sorted_step_names = sorted(steps_dict['steps'].keys())
diff --git a/build/android/pylib/perf/surface_stats_collector.py b/build/android/pylib/perf/surface_stats_collector.py
index c7e7527..98b7fed 100644
--- a/build/android/pylib/perf/surface_stats_collector.py
+++ b/build/android/pylib/perf/surface_stats_collector.py
@@ -1,191 +1,8 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-
-# 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)
+from devil.android.perf.surface_stats_collector import *
diff --git a/build/android/pylib/perf/surface_stats_collector_unittest.py b/build/android/pylib/perf/surface_stats_collector_unittest.py
deleted file mode 100644
index e905d73..0000000
--- a/build/android/pylib/perf/surface_stats_collector_unittest.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2013 The Chromium 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
index 0a0ace0..2764e42 100644
--- a/build/android/pylib/perf/test_options.py
+++ b/build/android/pylib/perf/test_options.py
@@ -17,4 +17,7 @@
     'single_step',
     'collect_chartjson_data',
     'output_chartjson_data',
+    'get_output_dir_archive',
+    'max_battery_temp',
+    'min_battery_level',
 ])
diff --git a/build/android/pylib/perf/test_runner.py b/build/android/pylib/perf/test_runner.py
index 3bee602..a580fd4 100644
--- a/build/android/pylib/perf/test_runner.py
+++ b/build/android/pylib/perf/test_runner.py
@@ -47,23 +47,54 @@
 """
 
 import collections
-import datetime
+import io
 import json
 import logging
 import os
 import pickle
+import re
 import shutil
 import sys
 import tempfile
 import threading
 import time
+import zipfile
 
-from pylib import cmd_helper
+from devil.android import battery_utils
+from devil.android import device_errors
+from devil.utils 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
+
+
+# Regex for the master branch commit position.
+_GIT_CR_POS_RE = re.compile(r'^Cr-Commit-Position: refs/heads/master@{#(\d+)}$')
+
+
+def _GetChromiumRevision():
+  """Get the git hash and commit position of the chromium master branch.
+
+  See: https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/slave/runtest.py#212
+
+  Returns:
+    A dictionary with 'revision' and 'commit_pos' keys.
+  """
+  status, output = cmd_helper.GetCmdStatusAndOutput(
+      ['git', 'log', '-n', '1', '--pretty=format:%H%n%B', 'HEAD'],
+      constants.DIR_SOURCE_ROOT)
+  revision = None
+  commit_pos = None
+  if not status:
+    lines = output.splitlines()
+    revision = lines[0]
+    for line in reversed(lines):
+      m = _GIT_CR_POS_RE.match(line.strip())
+      if m:
+        commit_pos = int(m.group(1))
+        break
+  return {'revision': revision, 'commit_pos': commit_pos}
 
 
 def GetPersistedResult(test_name):
@@ -86,7 +117,10 @@
 
     persisted_result = GetPersistedResult(k)
     if persisted_result:
+      data['start_time'] = persisted_result['start_time']
+      data['end_time'] = persisted_result['end_time']
       data['total_time'] = persisted_result['total_time']
+      data['has_archive'] = persisted_result['archive_bytes'] is not None
     step_values.append(data)
 
   with file(json_output, 'w') as o:
@@ -94,12 +128,13 @@
   return 0
 
 
-def PrintTestOutput(test_name, json_file_name=None):
+def PrintTestOutput(test_name, json_file_name=None, archive_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.
+    archive_file_name: name of the file to write the compressed ZIP archive.
 
   Returns:
     exit code generated by the test step.
@@ -111,12 +146,25 @@
   logging.info('Output from:')
   logging.info(persisted_result['cmd'])
   logging.info('*' * 80)
-  print persisted_result['output']
+
+  output_formatted = ''
+  persisted_outputs = persisted_result['output']
+  for i in xrange(len(persisted_outputs)):
+    output_formatted += '\n\nOutput from run #%d:\n\n%s' % (
+        i, persisted_outputs[i])
+  print output_formatted
 
   if json_file_name:
     with file(json_file_name, 'w') as f:
       f.write(persisted_result['chartjson'])
 
+  if archive_file_name:
+    if persisted_result['archive_bytes'] is not None:
+      with file(archive_file_name, 'wb') as f:
+        f.write(persisted_result['archive_bytes'])
+    else:
+      logging.error('The output dir was not archived.')
+
   return persisted_result['exit_code']
 
 
@@ -191,25 +239,18 @@
     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']
+    self._device_battery = battery_utils.BatteryUtils(self.device)
 
   @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))
+    pickled = os.path.join(constants.PERF_OUTPUT_DIR, result['name'])
+    if os.path.exists(pickled):
+      with file(pickled, 'r') as f:
+        previous = pickle.loads(f.read())
+        result['output'] = previous['output'] + result['output']
+
+    with file(pickled, 'w') as f:
+      f.write(pickle.dumps(result))
 
   def _CheckDeviceAffinity(self, test_name):
     """Returns True if test_name has affinity for this shard."""
@@ -231,8 +272,43 @@
       return ''
 
     json_output_path = os.path.join(self._output_dir, 'results-chart.json')
-    with open(json_output_path) as f:
-      return f.read()
+    try:
+      with open(json_output_path) as f:
+        return f.read()
+    except IOError:
+      logging.exception('Exception when reading chartjson.')
+      logging.error('This usually means that telemetry did not run, so it could'
+                    ' not generate the file. Please check the device running'
+                    ' the test.')
+      return ''
+
+  def _WriteBuildBotJson(self):
+    """Write metadata about the buildbot environment to the output dir."""
+    data = {
+      'chromium': _GetChromiumRevision(),
+      'environment': dict(os.environ)}
+    logging.info('BuildBot environment: %s', data)
+    with open(os.path.join(self._output_dir, 'buildbot.json'), 'w') as f:
+      json.dump(data, f, sort_keys=True, indent=2, separators=(',', ': '))
+
+  def _ArchiveOutputDir(self):
+    """Archive all files in the output dir, and return as compressed bytes."""
+    with io.BytesIO() as archive:
+      with zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED) as contents:
+        num_files = 0
+        for absdir, _, files in os.walk(self._output_dir):
+          reldir = os.path.relpath(absdir, self._output_dir)
+          for filename in files:
+            src_path = os.path.join(absdir, filename)
+            # We use normpath to turn './file.txt' into just 'file.txt'.
+            dst_path = os.path.normpath(os.path.join(reldir, filename))
+            contents.write(src_path, dst_path)
+            num_files += 1
+      if num_files:
+        logging.info('%d files in the output dir were archived.', num_files)
+      else:
+        logging.warning('No files in the output dir. Archive is empty.')
+      return archive.getvalue()
 
   def _LaunchPerfTest(self, test_name):
     """Runs a perf test.
@@ -249,22 +325,37 @@
     try:
       logging.warning('Unmapping device ports')
       forwarder.Forwarder.UnmapAllDevicePorts(self.device)
-      self.device.old_interface.RestartAdbdOnDevice()
-    except Exception as e:
+      self.device.RestartAdbd()
+    except Exception as e: # pylint: disable=broad-except
       logging.error('Exception when tearing down device %s', e)
 
-    cmd = ('%s --device %s' %
-           (self._tests['steps'][test_name]['cmd'],
-            self.device_serial))
+    test_config = self._tests['steps'][test_name]
+    cmd = ('%s --device %s' % (test_config['cmd'], self.device_serial))
 
-    if self._options.collect_chartjson_data:
+    if (self._options.collect_chartjson_data
+        or test_config.get('archive_output_dir')):
       self._output_dir = tempfile.mkdtemp()
+      self._WriteBuildBotJson()
       cmd = cmd + ' --output-dir=%s' % self._output_dir
 
-    logging.info('%s : %s', test_name, cmd)
-    start_time = datetime.datetime.now()
+    logging.info(
+        'temperature: %s (0.1 C)',
+        str(self._device_battery.GetBatteryInfo().get('temperature')))
+    if self._options.max_battery_temp:
+      self._device_battery.LetBatteryCoolToTemperature(
+          self._options.max_battery_temp)
 
-    timeout = self._tests['steps'][test_name].get('timeout', 5400)
+    logging.info('Charge level: %s%%',
+        str(self._device_battery.GetBatteryInfo().get('level')))
+    if self._options.min_battery_level:
+      self._device_battery.ChargeDeviceToLevel(
+          self._options.min_battery_level)
+    self.device.SetScreen(True)
+
+    logging.info('%s : %s', test_name, cmd)
+    start_time = time.time()
+
+    timeout = test_config.get('timeout', 3600)
     if self._options.no_timeout:
       timeout = None
     logging.info('Timeout for %s test: %s', test_name, timeout)
@@ -273,6 +364,7 @@
       full_cmd = 'echo %s' % cmd
 
     logfile = sys.stdout
+    archive_bytes = None
     if self._options.single_step:
       # Just print a heart-beat so that the outer buildbot scripts won't timeout
       # without response.
@@ -284,21 +376,38 @@
       exit_code, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
           full_cmd, timeout, cwd=cwd, shell=True, logfile=logfile)
       json_output = self._ReadChartjsonOutput()
+      if test_config.get('archive_output_dir'):
+        archive_bytes = self._ArchiveOutputDir()
     except cmd_helper.TimeoutError as e:
       exit_code = -1
-      output = str(e)
+      output = e.output
       json_output = ''
     finally:
       self._CleanupOutputDirectory()
       if self._options.single_step:
         logfile.stop()
-    end_time = datetime.datetime.now()
+    end_time = time.time()
     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,
+                 test_name, exit_code, end_time - start_time,
                  self.device_serial)
 
+    try:
+      # Some perf configs run the same benchmark with different options on
+      # different step names. Here we disambiguate those, so that data is
+      # uploaded to the perf dashoards based on their step name instead.
+      chart_data = json.loads(json_output)
+      if chart_data['benchmark_name'] != test_name:
+        logging.info('Benchmark %r will be reported as %r in chartjson.',
+                     chart_data['benchmark_name'], test_name)
+        chart_data['telemetry_benchmark_name'] = chart_data['benchmark_name']
+        chart_data['benchmark_name'] = test_name
+        json_output = json.dumps(chart_data, sort_keys=True, indent=2,
+                                 separators=(',', ': '))
+    except StandardError:
+      logging.exception('Could not read data from chartjson.')
+
     if exit_code == 0:
       result_type = base_test_result.ResultType.PASS
     else:
@@ -309,7 +418,7 @@
       try:
         self.device.WaitUntilFullyBooted(timeout=120)
       except device_errors.CommandTimeoutError as e:
-        logging.error('Device failed to return after %s: %s' % (test_name, 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:
@@ -321,12 +430,15 @@
 
     persisted_result = {
         'name': test_name,
-        'output': output,
+        'output': [output],
         'chartjson': json_output,
+        'archive_bytes': archive_bytes,
         'exit_code': exit_code,
         'actual_exit_code': actual_exit_code,
         'result_type': result_type,
-        'total_time': (end_time - start_time).seconds,
+        'start_time': start_time,
+        'end_time': end_time,
+        'total_time': end_time - start_time,
         'device': self.device_serial,
         'cmd': cmd,
     }
diff --git a/build/android/pylib/perf/thermal_throttle.py b/build/android/pylib/perf/thermal_throttle.py
index 383b6d5..0473da8 100644
--- a/build/android/pylib/perf/thermal_throttle.py
+++ b/build/android/pylib/perf/thermal_throttle.py
@@ -1,137 +1,8 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-
-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
-
+from devil.android.perf.thermal_throttle import *
diff --git a/build/android/pylib/remote/device/appurify_constants.py b/build/android/pylib/remote/device/appurify_constants.py
index 9343178..cf99bb6 100644
--- a/build/android/pylib/remote/device/appurify_constants.py
+++ b/build/android/pylib/remote/device/appurify_constants.py
@@ -54,4 +54,5 @@
   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
+  BOINGO = 49
+
diff --git a/build/android/pylib/remote/device/appurify_sanitized.py b/build/android/pylib/remote/device/appurify_sanitized.py
index 9f6ab40..a75d63d 100644
--- a/build/android/pylib/remote/device/appurify_sanitized.py
+++ b/build/android/pylib/remote/device/appurify_sanitized.py
@@ -15,8 +15,8 @@
     constants.DIR_SOURCE_ROOT, 'third_party', 'appurify-python', 'src'))
 handlers_before = list(logging.getLogger().handlers)
 
-import appurify.api
-import appurify.utils
+import appurify.api # pylint: disable=import-error
+import appurify.utils # pylint: disable=import-error
 
 handlers_after = list(logging.getLogger().handlers)
 new_handler = list(set(handlers_after) - set(handlers_before))
diff --git a/build/android/pylib/remote/device/remote_device_environment.py b/build/android/pylib/remote/device/remote_device_environment.py
index dc11845..7923f3a 100644
--- a/build/android/pylib/remote/device/remote_device_environment.py
+++ b/build/android/pylib/remote/device/remote_device_environment.py
@@ -11,12 +11,11 @@
 import random
 import sys
 
-from pylib import constants
+from devil.utils import reraiser_thread
+from devil.utils import timeout_retry
 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."""
@@ -125,6 +124,8 @@
         self._runner_package, args.runner_package, 'runner_package')
     self._runner_type = command_line_override(
         self._runner_type, args.runner_type, 'runner_type')
+    self._timeouts["in-progress"] = command_line_override(
+        self._timeouts["in-progress"], args.test_timeout, 'test_timeout')
 
     if args.api_key_file:
       with open(args.api_key_file) as api_key_file:
@@ -280,7 +281,7 @@
     timeout_retry.WaitFor(self._FindDevice, wait_period=1)
 
   def _PrintAvailableDevices(self, device_list):
-    def compare_devices(a,b):
+    def compare_devices(a, b):
       for key in ('os_version', 'name'):
         c = cmp(a[key], b[key])
         if c:
@@ -331,11 +332,6 @@
     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
 
diff --git a/build/android/pylib/remote/device/remote_device_gtest_run.py b/build/android/pylib/remote/device/remote_device_gtest_run.py
index 4c645b0..0cfe717 100644
--- a/build/android/pylib/remote/device/remote_device_gtest_run.py
+++ b/build/android/pylib/remote/device/remote_device_gtest_run.py
@@ -6,22 +6,16 @@
 
 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.gtest import gtest_test_instance
 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):
@@ -52,17 +46,29 @@
 
     dummy_app_path = os.path.join(
         constants.GetOutDirectory(), 'apks', 'remote_device_dummy.apk')
+
+    # pylint: disable=protected-access
     with tempfile.NamedTemporaryFile(suffix='.flags.txt') as flag_file:
-      env_vars = {}
+      env_vars = dict(self._test_instance.extras)
+      if gtest_test_instance.EXTRA_SHARD_NANO_TIMEOUT not in env_vars:
+        env_vars[gtest_test_instance.EXTRA_SHARD_NANO_TIMEOUT] = int(
+            self._test_instance.shard_timeout * 1e9)
+
+      flags = []
+
       filter_string = self._test_instance._GenerateDisabledFilterString(None)
       if filter_string:
-        flag_file.write('_ --gtest_filter=%s' % filter_string)
+        flags.append('--gtest_filter=%s' % filter_string)
+
+      if self._test_instance.test_arguments:
+        flags.append(self._test_instance.test_arguments)
+
+      if flags:
+        flag_file.write('_ ' + ' '.join(flags))
         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)
@@ -78,10 +84,6 @@
               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))
+
+    self._DetectPlatformErrors(results)
     return results
diff --git a/build/android/pylib/remote/device/remote_device_helper.py b/build/android/pylib/remote/device/remote_device_helper.py
index 896ae99..1b02207 100644
--- a/build/android/pylib/remote/device/remote_device_helper.py
+++ b/build/android/pylib/remote/device/remote_device_helper.py
@@ -4,7 +4,7 @@
 
 """Common functions and Exceptions for remote_device_*"""
 
-from pylib.utils import base_error
+from devil import base_error
 
 
 class RemoteDeviceError(base_error.BaseError):
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
index bcdb90c..8858b06 100644
--- a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
@@ -8,10 +8,8 @@
 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(
@@ -27,6 +25,7 @@
     """Set up the triggering of a test run."""
     logging.info('Triggering test run.')
 
+    # pylint: disable=protected-access
     with tempfile.NamedTemporaryFile(suffix='.txt') as test_list_file:
       tests = self._test_instance.GetTests()
       logging.debug('preparing to run %d instrumentation tests remotely:',
@@ -52,7 +51,8 @@
           self._test_instance.driver_apk,
           self._test_instance.driver_name,
           environment_variables=env_vars,
-          extra_apks=[self._test_instance.test_apk])
+          extra_apks=([self._test_instance.test_apk] +
+                      self._test_instance.additional_apks))
 
   #override
   def _ParseTestResults(self):
@@ -71,4 +71,5 @@
     else:
       raise Exception('Unexpected result type: %s' % type(result).__name__)
 
+    self._DetectPlatformErrors(r)
     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
index 60cc735..ec29b55 100644
--- a/build/android/pylib/remote/device/remote_device_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_test_run.py
@@ -7,17 +7,23 @@
 import json
 import logging
 import os
-import sys
+import re
+import shutil
+import string
 import tempfile
 import time
 import zipfile
 
-from pylib import constants
+from devil.utils import zip_utils
+from pylib.base import base_test_result
 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
+
+_DEVICE_OFFLINE_RE = re.compile('error: device not found')
+_LONG_MSG_RE = re.compile('longMsg=(.*)$')
+_SHORT_MSG_RE = re.compile('shortMsg=(.*)$')
 
 class RemoteDeviceTestRun(test_run.TestRun):
   """Run tests on a remote device."""
@@ -43,6 +49,7 @@
     self._test_id = ''
     self._results = ''
     self._test_run_id = ''
+    self._results_temp_dir = None
 
   #override
   def SetUp(self):
@@ -73,7 +80,7 @@
       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)
+      logging.info('Test run id: %s', self._test_run_id)
 
     if self._env.collect:
       current_status = ''
@@ -129,6 +136,8 @@
             self._env.token, self._test_run_id, reason='Test runner exiting.')
       remote_device_helper.TestHttpResponse(test_abort_res,
                                             'Unable to abort test.')
+    if self._results_temp_dir:
+      shutil.rmtree(self._results_temp_dir)
 
   def __enter__(self):
     """Set up the test run when used as a context manager."""
@@ -172,17 +181,29 @@
   def _DownloadTestResults(self, results_path):
     """Download the test results from remote device service.
 
+    Downloads results in temporary location, and then copys results
+    to results_path if results_path is not set to None.
+
     Args:
       results_path: Path to download appurify results zipfile.
+
+    Returns:
+      Path to downloaded file.
     """
-    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))
+
+    if self._results_temp_dir is None:
+      self._results_temp_dir = tempfile.mkdtemp()
+      logging.info('Downloading results to %s.', self._results_temp_dir)
       with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
                                               logging.WARNING):
         appurify_sanitized.utils.wget(self._results['results']['url'],
-                                      results_path)
+                                      self._results_temp_dir + '/results')
+    if results_path:
+      logging.info('Copying results to %s', results_path)
+      if not os.path.exists(os.path.dirname(results_path)):
+        os.makedirs(os.path.dirname(results_path))
+      shutil.copy(self._results_temp_dir + '/results', results_path)
+    return self._results_temp_dir + '/results'
 
   def _GetTestStatus(self, test_run_id):
     """Checks the state of the test, and sets self._results
@@ -225,7 +246,7 @@
               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));
+            zip_utils.WriteToZipFile(zip_file, a, os.path.basename(a))
             additional_apks.append(os.path.basename(a))
 
         config['sdcard_files'] = ','.join(sdcard_files)
@@ -237,7 +258,7 @@
     else:
       self._test_id = self._UploadTestToDevice('robotium', test_path)
 
-    logging.info('Setting config: %s' % config)
+    logging.info('Setting config: %s', config)
     appurify_configs = {}
     if self._env.network_config:
       appurify_configs['network'] = self._env.network_config
@@ -261,7 +282,7 @@
     Args:
       test_type: Type of test that is being uploaded. Ex. uirobot, gtest..
     """
-    logging.info('Uploading %s to remote service.' % test_path)
+    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):
@@ -306,3 +327,64 @@
             self._env.token, config, self._test_id)
       remote_device_helper.TestHttpResponse(
           config_response, 'Unable to upload test config.')
+
+  def _LogLogcat(self, level=logging.CRITICAL):
+    """Prints out logcat downloaded from remote service.
+    Args:
+      level: logging level to print at.
+
+    Raises:
+      KeyError: If appurify_results/logcat.txt file cannot be found in
+                downloaded zip.
+    """
+    zip_file = self._DownloadTestResults(None)
+    with zipfile.ZipFile(zip_file) as z:
+      try:
+        logcat = z.read('appurify_results/logcat.txt')
+        printable_logcat = ''.join(c for c in logcat if c in string.printable)
+        for line in printable_logcat.splitlines():
+          logging.log(level, line)
+      except KeyError:
+        logging.error('No logcat found.')
+
+  def _LogAdbTraceLog(self):
+    zip_file = self._DownloadTestResults(None)
+    with zipfile.ZipFile(zip_file) as z:
+      adb_trace_log = z.read('adb_trace.log')
+      for line in adb_trace_log.splitlines():
+        logging.critical(line)
+
+  def _DidDeviceGoOffline(self):
+    zip_file = self._DownloadTestResults(None)
+    with zipfile.ZipFile(zip_file) as z:
+      adb_trace_log = z.read('adb_trace.log')
+      if any(_DEVICE_OFFLINE_RE.search(l) for l in adb_trace_log.splitlines()):
+        return True
+    return False
+
+  def _DetectPlatformErrors(self, results):
+    if not self._results['results']['pass']:
+      crash_msg = None
+      for line in self._results['results']['output'].splitlines():
+        m = _LONG_MSG_RE.search(line)
+        if m:
+          crash_msg = m.group(1)
+          break
+        m = _SHORT_MSG_RE.search(line)
+        if m:
+          crash_msg = m.group(1)
+      if crash_msg:
+        self._LogLogcat()
+        results.AddResult(base_test_result.BaseTestResult(
+            crash_msg, base_test_result.ResultType.CRASH))
+      elif self._DidDeviceGoOffline():
+        self._LogLogcat()
+        self._LogAdbTraceLog()
+        raise remote_device_helper.RemoteDeviceError(
+            'Remote service unable to reach device.', is_infra_error=True)
+      else:
+        # Remote service is reporting a failure, but no failure in results obj.
+        if results.DidRunPass():
+          results.AddResult(base_test_result.BaseTestResult(
+              'Remote service detected error.',
+              base_test_result.ResultType.UNKNOWN))
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
index f818c98..f99e685 100644
--- a/build/android/pylib/remote/device/remote_device_uirobot_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_uirobot_test_run.py
@@ -5,10 +5,7 @@
 """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
diff --git a/build/android/pylib/results/flakiness_dashboard/json_results_generator.py b/build/android/pylib/results/flakiness_dashboard/json_results_generator.py
index e5c433d..7f849f9 100644
--- a/build/android/pylib/results/flakiness_dashboard/json_results_generator.py
+++ b/build/android/pylib/results/flakiness_dashboard/json_results_generator.py
@@ -62,7 +62,7 @@
     trie[path] = value
     return
 
-  directory, _slash, rest = path.partition('/')
+  directory, _, rest = path.partition('/')
   if not directory in trie:
     trie[directory] = {}
   AddPathToTrie(rest, value, trie[directory])
@@ -237,8 +237,8 @@
 
     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)
+      _log.debug('Builder name (%s) is not in the results.json file.',
+                 builder_name)
 
     self._ConvertJSONToCurrentVersion(results_json)
 
@@ -297,12 +297,11 @@
           _log.info('JSON uploaded.')
         else:
           _log.debug(
-              "JSON upload failed, %d: '%s'" %
-              (response.code, response.read()))
+              "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)
+    except Exception, err: # pylint: disable=broad-except
+      _log.error('Upload failed: %s', err)
       return
 
   def _GetTestTiming(self, test_name):
@@ -398,7 +397,7 @@
 
       try:
         results_json = json.loads(old_results)
-      except Exception:
+      except Exception: # pylint: disable=broad-except
         _log.debug('results.json was not valid JSON. Clobbering.')
         # The JSON file is not valid JSON. Just clobber the results.
         results_json = {}
@@ -645,7 +644,7 @@
         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))
+                  'Retrying in 10 seconds...', e.code, e.filename)
         time.sleep(10)
 
 
diff --git a/build/android/pylib/utils/json_results_generator_unittest.py b/build/android/pylib/results/flakiness_dashboard/json_results_generator_unittest.py
similarity index 98%
rename from build/android/pylib/utils/json_results_generator_unittest.py
rename to build/android/pylib/results/flakiness_dashboard/json_results_generator_unittest.py
index 41ab77b..d6aee05 100644
--- a/build/android/pylib/utils/json_results_generator_unittest.py
+++ b/build/android/pylib/results/flakiness_dashboard/json_results_generator_unittest.py
@@ -10,7 +10,7 @@
 import unittest
 import json
 
-from pylib.utils import json_results_generator
+from pylib.results.flakiness_dashboard import json_results_generator
 
 
 class JSONGeneratorTest(unittest.TestCase):
diff --git a/build/android/pylib/results/flakiness_dashboard/results_uploader.py b/build/android/pylib/results/flakiness_dashboard/results_uploader.py
index 856fa9c..1360b80 100644
--- a/build/android/pylib/results/flakiness_dashboard/results_uploader.py
+++ b/build/android/pylib/results/flakiness_dashboard/results_uploader.py
@@ -12,7 +12,7 @@
 import xml
 
 
-from pylib import cmd_helper
+from devil.utils import cmd_helper
 from pylib import constants
 from pylib.results.flakiness_dashboard import json_results_generator
 from pylib.utils import repo_utils
@@ -106,6 +106,9 @@
       buildbot_branch = os.environ.get('BUILDBOT_BRANCH')
       if not buildbot_branch:
         buildbot_branch = 'master'
+      else:
+        # Ensure there's no leading "origin/"
+        buildbot_branch = buildbot_branch[buildbot_branch.find('/') + 1:]
       self._master_name = '%s-%s' % (self._build_name, buildbot_branch)
 
     self._test_results_map = {}
@@ -159,8 +162,8 @@
       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)
+    except Exception as e: # pylint: disable=broad-except
+      logging.error("Uploading results to test server failed: %s.", e)
     finally:
       shutil.rmtree(tmp_folder)
 
diff --git a/build/android/pylib/results/json_results.py b/build/android/pylib/results/json_results.py
index 65664e3..1a60f64 100644
--- a/build/android/pylib/results/json_results.py
+++ b/build/android/pylib/results/json_results.py
@@ -3,15 +3,14 @@
 # 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.
+def GenerateResultsDict(test_run_results):
+  """Create a results dict from |test_run_results| suitable for writing to JSON.
   Args:
-    test_run_result: a base_test_result.TestRunResults object.
+    test_run_results: a list of base_test_result.TestRunResults objects.
   Returns:
     A results dict that mirrors the one generated by
       base/test/launcher/test_results_tracker.cc:SaveSummaryAsJSON.
@@ -45,11 +44,30 @@
   #         },
   #       ],
   #     },
+  #     {
+  #       "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'
@@ -64,29 +82,28 @@
     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 = set()
+  per_iteration_data = []
+  for test_run_result in test_run_results:
+    iteration_data = {
+      t.GetName(): [{
+        'status': status_as_string(t.GetType()),
+        'elapsed_time_ms': t.GetDuration(),
+        'output_snippet': '',
+        'losless_snippet': '',
+        'output_snippet_base64:': '',
+      }]
+      for t in test_run_result.GetAll()
     }
-
-  all_tests_tuple, per_iteration_data_tuple = zip(
-      *[(t.GetName(), generate_iteration_data(t))
-        for t in test_run_result.GetAll()])
+    all_tests = all_tests.union(set(iteration_data.iterkeys()))
+    per_iteration_data.append(iteration_data)
 
   return {
     'global_tags': [],
-    'all_tests': list(all_tests_tuple),
+    'all_tests': sorted(list(all_tests)),
     # TODO(jbudorick): Add support for disabled tests within base_test_result.
     'disabled_tests': [],
-    'per_iteration_data': list(per_iteration_data_tuple),
+    'per_iteration_data': per_iteration_data,
   }
 
 
diff --git a/build/android/pylib/results/json_results_test.py b/build/android/pylib/results/json_results_test.py
index 1bc730d..648f2c8 100755
--- a/build/android/pylib/results/json_results_test.py
+++ b/build/android/pylib/results/json_results_test.py
@@ -18,7 +18,7 @@
     all_results = base_test_result.TestRunResults()
     all_results.AddResult(result)
 
-    results_dict = json_results.GenerateResultsDict(all_results)
+    results_dict = json_results.GenerateResultsDict([all_results])
     self.assertEquals(
         ['test.package.TestName'],
         results_dict['all_tests'])
@@ -39,7 +39,7 @@
     all_results = base_test_result.TestRunResults()
     all_results.AddResult(result)
 
-    results_dict = json_results.GenerateResultsDict(all_results)
+    results_dict = json_results.GenerateResultsDict([all_results])
     self.assertEquals(
         ['test.package.TestName'],
         results_dict['all_tests'])
@@ -60,7 +60,7 @@
     all_results = base_test_result.TestRunResults()
     all_results.AddResult(result)
 
-    results_dict = json_results.GenerateResultsDict(all_results)
+    results_dict = json_results.GenerateResultsDict([all_results])
     self.assertEquals(
         ['test.package.TestName'],
         results_dict['all_tests'])
@@ -81,7 +81,7 @@
     all_results = base_test_result.TestRunResults()
     all_results.AddResult(result)
 
-    results_dict = json_results.GenerateResultsDict(all_results)
+    results_dict = json_results.GenerateResultsDict([all_results])
     self.assertEquals(
         ['test.package.TestName'],
         results_dict['all_tests'])
@@ -105,25 +105,26 @@
     all_results.AddResult(result1)
     all_results.AddResult(result2)
 
-    results_dict = json_results.GenerateResultsDict(all_results)
+    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']))
+
+    self.assertTrue('per_iteration_data' in results_dict)
+    iterations = results_dict['per_iteration_data']
+    self.assertEquals(1, len(iterations))
 
     expected_tests = set([
         'test.package.TestName1',
         'test.package.TestName2',
     ])
 
-    for iteration_result in results_dict['per_iteration_data']:
+    for test_name, iteration_result in iterations[0].iteritems():
+      self.assertTrue(test_name in expected_tests)
+      expected_tests.remove(test_name)
       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]
+      test_iteration_result = iteration_result[0]
       self.assertTrue('status' in test_iteration_result)
       self.assertEquals('SUCCESS', test_iteration_result['status'])
 
diff --git a/build/android/pylib/results/report_results.py b/build/android/pylib/results/report_results.py
index 4c9518e..001850f 100644
--- a/build/android/pylib/results/report_results.py
+++ b/build/android/pylib/results/report_results.py
@@ -24,9 +24,9 @@
       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)
 
-  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),
@@ -36,14 +36,17 @@
 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))
+  logging.info('Upload results for test type "%s", test package "%s" to %s',
+               test_type, test_package, flakiness_server)
 
   try:
-    if test_type == 'Instrumentation':
+    # TODO(jbudorick): remove Instrumentation once instrumentation tests
+    # switch to platform mode.
+    if test_type in ('instrumentation', 'Instrumentation'):
       if flakiness_server == constants.UPSTREAM_FLAKINESS_SERVER:
         assert test_package in ['ContentShellTest',
-                                'ChromeShellTest',
+                                'ChromePublicTest',
+                                'ChromeSyncShellTest',
                                 'AndroidWebViewTest']
         dashboard_test_type = ('%s_instrumentation_tests' %
                                test_package.lower().rstrip('test'))
@@ -51,7 +54,7 @@
       else:
         dashboard_test_type = 'Chromium_Android_Instrumentation'
 
-    elif test_type == 'Unit test':
+    elif test_type == 'gtest':
       dashboard_test_type = test_package
 
     else:
@@ -61,8 +64,8 @@
     results_uploader.Upload(
         results, flakiness_server, dashboard_test_type)
 
-  except Exception as e:
-    logging.error(e)
+  except Exception: # pylint: disable=broad-except
+    logging.exception('Failure while logging to %s', flakiness_server)
 
 
 def LogFull(results, test_type, test_package, annotation=None,
diff --git a/build/android/pylib/screenshot.py b/build/android/pylib/screenshot.py
index 0fcc590..b3d17e2 100644
--- a/build/android/pylib/screenshot.py
+++ b/build/android/pylib/screenshot.py
@@ -7,13 +7,8 @@
 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
+from devil.android import device_signal
+from devil.utils import cmd_helper
 
 
 class VideoRecorder(object):
@@ -30,9 +25,6 @@
   """
   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())
diff --git a/build/android/pylib/uiautomator/__init__.py b/build/android/pylib/sdk/__init__.py
similarity index 61%
copy from build/android/pylib/uiautomator/__init__.py
copy to build/android/pylib/sdk/__init__.py
index cda7672..50b23df 100644
--- a/build/android/pylib/uiautomator/__init__.py
+++ b/build/android/pylib/sdk/__init__.py
@@ -1,4 +1,3 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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/sdk/aapt.py b/build/android/pylib/sdk/aapt.py
new file mode 100644
index 0000000..96fbf9c
--- /dev/null
+++ b/build/android/pylib/sdk/aapt.py
@@ -0,0 +1,8 @@
+# Copyright 2015 The Chromium 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-wildcard-import
+# pylint: disable=wildcard-import
+
+from devil.android.sdk.aapt import *
diff --git a/build/android/pylib/sdk/dexdump.py b/build/android/pylib/sdk/dexdump.py
new file mode 100644
index 0000000..f7357f7
--- /dev/null
+++ b/build/android/pylib/sdk/dexdump.py
@@ -0,0 +1,8 @@
+# Copyright 2015 The Chromium 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-wildcard-import
+# pylint: disable=wildcard-import
+
+from devil.android.sdk.dexdump import *
diff --git a/build/android/pylib/sdk/split_select.py b/build/android/pylib/sdk/split_select.py
new file mode 100644
index 0000000..6adb106
--- /dev/null
+++ b/build/android/pylib/sdk/split_select.py
@@ -0,0 +1,8 @@
+# Copyright 2015 The Chromium 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-wildcard-import
+# pylint: disable=wildcard-import
+
+from devil.android.sdk.split_select import *
diff --git a/build/android/pylib/system_properties.py b/build/android/pylib/system_properties.py
deleted file mode 100644
index 3f16f86..0000000
--- a/build/android/pylib/system_properties.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2013 The Chromium 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/setup.py b/build/android/pylib/uiautomator/setup.py
deleted file mode 100644
index bd8ffc7..0000000
--- a/build/android/pylib/uiautomator/setup.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2013 The Chromium 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
deleted file mode 100644
index 3f5f950..0000000
--- a/build/android/pylib/uiautomator/test_options.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2013 The Chromium 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
deleted file mode 100644
index cb51fdf..0000000
--- a/build/android/pylib/uiautomator/test_package.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (c) 2013 The Chromium 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
deleted file mode 100644
index 296bd47..0000000
--- a/build/android/pylib/uiautomator/test_runner.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright (c) 2013 The Chromium 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/uirobot_test_instance.py b/build/android/pylib/uirobot/uirobot_test_instance.py
index e3f6eb7..1891ab7 100644
--- a/build/android/pylib/uirobot/uirobot_test_instance.py
+++ b/build/android/pylib/uirobot/uirobot_test_instance.py
@@ -2,13 +2,11 @@
 # 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 devil.android import apk_helper
 from pylib.base import test_instance
-from pylib.utils import apk_helper
 
 class UirobotTestInstance(test_instance.TestInstance):
 
diff --git a/build/android/pylib/utils/apk_helper.py b/build/android/pylib/utils/apk_helper.py
index f5e9cd3..dd45807 100644
--- a/build/android/pylib/utils/apk_helper.py
+++ b/build/android/pylib/utils/apk_helper.py
@@ -1,76 +1,8 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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."""
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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
+from devil.android.apk_helper import *
diff --git a/build/android/pylib/utils/base_error.py b/build/android/pylib/utils/base_error.py
index 31eaa54..263479a 100644
--- a/build/android/pylib/utils/base_error.py
+++ b/build/android/pylib/utils/base_error.py
@@ -2,15 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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
+from devil.base_error import *
diff --git a/build/android/pylib/utils/device_temp_file.py b/build/android/pylib/utils/device_temp_file.py
index 7d3b95b..ae1edc8 100644
--- a/build/android/pylib/utils/device_temp_file.py
+++ b/build/android/pylib/utils/device_temp_file.py
@@ -1,57 +1,8 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-# 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()
+from devil.android.device_temp_file import *
diff --git a/build/android/pylib/utils/device_temp_file_test.py b/build/android/pylib/utils/device_temp_file_test.py
deleted file mode 100755
index f839ce0..0000000
--- a/build/android/pylib/utils/device_temp_file_test.py
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/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
index 635462f..a74c06a 100644
--- a/build/android/pylib/utils/emulator.py
+++ b/build/android/pylib/utils/emulator.py
@@ -14,17 +14,14 @@
 import subprocess
 import time
 
-# TODO(craigdh): Move these pylib dependencies to pylib/utils/.
-from pylib import cmd_helper
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.android.sdk import adb_wrapper
+from devil.utils 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'
 
@@ -52,7 +49,7 @@
 hw.device.name=Galaxy Nexus
 hw.battery=yes
 hw.sensors.proximity=yes
-image.sysdir.1=system-images/android-{api.level}/{abi.type}/
+image.sysdir.1=system-images/android-{api.level}/default/{abi.type}/
 hw.sensors.orientation=yes
 hw.audioInput=yes
 hw.camera.front=none
@@ -82,21 +79,23 @@
   """Emulator failed to launch."""
   pass
 
-def _KillAllEmulators():
+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.
+  running but a device slot is taken.  A little bot trouble and we're out of
+  room forever.
   """
-  emulators = [d for d in device_utils.HealthyDevices() if d.adb.is_emulator]
+  emulators = [device_utils.DeviceUtils(a)
+               for a in adb_wrapper.AdbWrapper.Devices()
+               if a.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()):
+    if not any(a.is_emulator for a in adb_wrapper.AdbWrapper.Devices()):
       return
     time.sleep(1)
 
@@ -114,7 +113,7 @@
     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)
+      logging.info('Delete AVD %s', avd_name)
 
 
 class PortPool(object):
@@ -140,7 +139,9 @@
 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]
+  emulators = [device_utils.DeviceUtils(a)
+               for a in adb_wrapper.AdbWrapper.Devices()
+               if a.is_emulator]
   for emulator in emulators:
     used_ports.append(emulator.adb.GetDeviceSerial().split('-')[1])
   for port in PortPool.port_range():
@@ -233,7 +234,7 @@
       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')
+    android_sdk_root = constants.ANDROID_SDK_ROOT
     self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator')
     self.android = os.path.join(android_sdk_root, 'tools', 'android')
     self.popen = None
@@ -333,7 +334,7 @@
     If fails, an exception will be raised.
     """
     if kill_all_emulators:
-      _KillAllEmulators()  # just to be sure
+      KillAllEmulators()  # just to be sure
     self._AggressiveImageCleanup()
     (self.device_serial, port) = self._DeviceName()
     emulator_command = [
diff --git a/build/android/pylib/utils/findbugs.py b/build/android/pylib/utils/findbugs.py
index 8deb0fe..ee2d5a7 100644
--- a/build/android/pylib/utils/findbugs.py
+++ b/build/android/pylib/utils/findbugs.py
@@ -2,15 +2,11 @@
 # 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 devil.utils import cmd_helper
 from pylib import constants
 
 
@@ -142,12 +138,16 @@
   cmd.extend(os.path.abspath(j) for j in jars or [])
 
   if output_file:
-    cmd_helper.RunCmd(cmd)
+    _, _, stderr = cmd_helper.GetCmdStatusOutputAndError(cmd)
+
     results_doc = xml.dom.minidom.parse(output_file)
   else:
-    raw_out = cmd_helper.GetCmdOutput(cmd)
+    _, raw_out, stderr = cmd_helper.GetCmdStatusOutputAndError(cmd)
     results_doc = xml.dom.minidom.parseString(raw_out)
 
+  for line in stderr.splitlines():
+    logging.debug('  %s', line)
+
   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
deleted file mode 100644
index 389ac43..0000000
--- a/build/android/pylib/utils/host_path_finder.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2013 The Chromium 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
index 580721f..ba8c9d2 100644
--- a/build/android/pylib/utils/host_utils.py
+++ b/build/android/pylib/utils/host_utils.py
@@ -1,16 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-
-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
-
+from devil.utils.host_utils import *
diff --git a/build/android/pylib/utils/isolator.py b/build/android/pylib/utils/isolator.py
index cac39d8..3e8b643 100644
--- a/build/android/pylib/utils/isolator.py
+++ b/build/android/pylib/utils/isolator.py
@@ -7,8 +7,9 @@
 import os
 import shutil
 import sys
+import tempfile
 
-from pylib import cmd_helper
+from devil.utils import cmd_helper
 from pylib import constants
 
 
@@ -49,19 +50,19 @@
     'use_ozone': '0',
     'use_x11': '0',
     'v8_use_external_startup_data': '1',
+    'msvs_version': '0',
   }
 
 
 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 __init__(self):
+    self._isolate_deps_dir = tempfile.mkdtemp()
+
+  @property
+  def isolate_deps_dir(self):
+    return self._isolate_deps_dir
 
   def Clear(self):
     """Deletes the isolate dependency directory."""
@@ -164,7 +165,8 @@
         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())
+    deps_product_dir = os.path.join(
+        deps_out_dir, os.path.basename(constants.GetOutDirectory()))
     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)
diff --git a/build/android/pylib/utils/logging_utils.py b/build/android/pylib/utils/logging_utils.py
index 1e46fa8..326a8b0 100644
--- a/build/android/pylib/utils/logging_utils.py
+++ b/build/android/pylib/utils/logging_utils.py
@@ -4,6 +4,75 @@
 
 import contextlib
 import logging
+import os
+import sys
+
+from pylib import constants
+sys.path.insert(0, os.path.join(constants.DIR_SOURCE_ROOT,
+                                'third_party', 'colorama', 'src'))
+import colorama
+
+class ColorStreamHandler(logging.StreamHandler):
+  """Handler that can be used to colorize logging output.
+
+  Example using a specific logger:
+
+    logger = logging.getLogger('my_logger')
+    logger.addHandler(ColorStreamHandler())
+    logger.info('message')
+
+  Example using the root logger:
+
+    ColorStreamHandler.MakeDefault()
+    logging.info('message')
+
+  """
+  # pylint does not see members added dynamically in the constructor.
+  # pylint: disable=no-member
+  color_map = {
+    logging.DEBUG: colorama.Fore.CYAN,
+    logging.WARNING: colorama.Fore.YELLOW,
+    logging.ERROR: colorama.Fore.RED,
+    logging.CRITICAL: colorama.Back.RED + colorama.Style.BRIGHT,
+  }
+
+  def __init__(self, force_color=False):
+    super(ColorStreamHandler, self).__init__()
+    self.force_color = force_color
+
+  @property
+  def is_tty(self):
+    isatty = getattr(self.stream, 'isatty', None)
+    return isatty and isatty()
+
+  #override
+  def format(self, record):
+    message = logging.StreamHandler.format(self, record)
+    if self.force_color or self.is_tty:
+      return self.Colorize(message, record.levelno)
+    return message
+
+  def Colorize(self, message, log_level):
+    try:
+      return self.color_map[log_level] + message + colorama.Style.RESET_ALL
+    except KeyError:
+      return message
+
+  @staticmethod
+  def MakeDefault(force_color=False):
+     """
+     Replaces the default logging handlers with a coloring handler. To use
+     a colorizing handler at the same time as others, either register them
+     after this call, or add the ColorStreamHandler on the logger using
+     Logger.addHandler()
+
+     Args:
+       force_color: Set to True to bypass the tty check and always colorize.
+     """
+     # If the existing handlers aren't removed, messages are duplicated
+     logging.getLogger().handlers = []
+     logging.getLogger().addHandler(ColorStreamHandler(force_color))
+
 
 @contextlib.contextmanager
 def SuppressLogging(level=logging.ERROR):
diff --git a/build/android/pylib/utils/md5sum.py b/build/android/pylib/utils/md5sum.py
index ed2e6bc..a8fedcc 100644
--- a/build/android/pylib/utils/md5sum.py
+++ b/build/android/pylib/utils/md5sum.py
@@ -1,85 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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} {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:
-      md5sum_script = (
-          MD5SUM_DEVICE_SCRIPT_FORMAT.format(
-              path=p, md5sum_lib=MD5SUM_DEVICE_LIB_PATH,
-              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)
-
+from devil.android.md5sum import *
diff --git a/build/android/pylib/utils/mock_calls.py b/build/android/pylib/utils/mock_calls.py
index 59167ba..c65109d 100644
--- a/build/android/pylib/utils/mock_calls.py
+++ b/build/android/pylib/utils/mock_calls.py
@@ -1,182 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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.
-"""
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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))
-
+from devil.utils.mock_calls import *
diff --git a/build/android/pylib/utils/parallelizer.py b/build/android/pylib/utils/parallelizer.py
index 9a85b54..49b18f0 100644
--- a/build/android/pylib/utils/parallelizer.py
+++ b/build/android/pylib/utils/parallelizer.py
@@ -1,242 +1,8 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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.
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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
-
+from devil.utils.parallelizer import *
diff --git a/build/android/pylib/utils/proguard.py b/build/android/pylib/utils/proguard.py
index 34ad5c3..5eda6be 100644
--- a/build/android/pylib/utils/proguard.py
+++ b/build/android/pylib/utils/proguard.py
@@ -6,23 +6,33 @@
 import re
 import tempfile
 
+from devil.utils import cmd_helper
 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'^(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_ANNOTATION_RE = re.compile(r'^(\s*?)- Annotation \[L(\S*);\]:$')
+_ELEMENT_PRIMITIVE = 0
+_ELEMENT_ARRAY = 1
+_ELEMENT_ANNOTATION = 2
+_PROGUARD_ELEMENT_RES = [
+  (_ELEMENT_PRIMITIVE,
+   re.compile(r'^(\s*?)- Constant element value \[(\S*) .*\]$')),
+  (_ELEMENT_ARRAY,
+   re.compile(r'^(\s*?)- Array element value \[(\S*)\]:$')),
+  (_ELEMENT_ANNOTATION,
+   re.compile(r'^(\s*?)- Annotation element value \[(\S*)\]:$'))
+]
+_PROGUARD_INDENT_WIDTH = 2
+_PROGUARD_ANNOTATION_VALUE_RE = re.compile(r'^(\s*?)- \S+? \[(.*)\]$')
 
 _PROGUARD_PATH_SDK = os.path.join(
-    constants.ANDROID_SDK_ROOT, 'tools', 'proguard', 'lib', 'proguard.jar')
+    constants.PROGUARD_ROOT, 'lib', 'proguard.jar')
 _PROGUARD_PATH_BUILT = (
     os.path.join(os.environ['ANDROID_BUILD_TOP'], 'external', 'proguard',
                  'lib', 'proguard.jar')
@@ -44,11 +54,11 @@
           {
             'class': '',
             'superclass': '',
-            'annotations': {},
+            'annotations': {/* dict -- see below */},
             'methods': [
               {
                 'method': '',
-                'annotations': {},
+                'annotations': {/* dict -- see below */},
               },
               ...
             ],
@@ -56,6 +66,31 @@
           ...
         ],
       }
+
+    Annotations dict format:
+      {
+        'empty-annotation-class-name': None,
+        'annotation-class-name': {
+          'field': 'primitive-value',
+          'field': [ 'array-item-1', 'array-item-2', ... ],
+          'field': {
+            /* Object value */
+            'field': 'primitive-value',
+            'field': [ 'array-item-1', 'array-item-2', ... ],
+            'field': { /* Object value */ }
+          }
+        }
+      }
+
+    Note that for top-level annotations their class names are used for
+    identification, whereas for any nested annotations the corresponding
+    field names are used.
+
+    One drawback of this approach is that an array containing empty
+    annotation classes will be represented as an array of 'None' values,
+    thus it will not be possible to find out annotation class names.
+    On the other hand, storing both annotation class name and the field name
+    would produce a very complex JSON.
   """
 
   with tempfile.NamedTemporaryFile() as proguard_output:
@@ -67,82 +102,189 @@
                        '-dontobfuscate',
                        '-dontpreverify',
                        '-dump', proguard_output.name])
+    return Parse(proguard_output)
 
+class _AnnotationElement(object):
+  def __init__(self, name, ftype, depth):
+    self.ref = None
+    self.name = name
+    self.ftype = ftype
+    self.depth = depth
 
-    results = {
-      'classes': [],
+class _ParseState(object):
+  _INITIAL_VALUES = (lambda: None, list, dict)
+  # Empty annotations are represented as 'None', not as an empty dictionary.
+  _LAZY_INITIAL_VALUES = (lambda: None, list, lambda: None)
+
+  def __init__(self):
+    self._class_result = None
+    self._method_result = None
+    self._parse_annotations = False
+    self._annotation_stack = []
+
+  def ResetPerSection(self, section_name):
+    self.InitMethod(None)
+    self._parse_annotations = (
+      section_name in ['Class file attributes', 'Methods'])
+
+  def ParseAnnotations(self):
+    return self._parse_annotations
+
+  def CreateAndInitClass(self, class_name):
+    self.InitMethod(None)
+    self._class_result = {
+      'class': class_name,
+      'superclass': '',
+      'annotations': {},
+      'methods': [],
     }
+    return self._class_result
 
-    annotation = None
-    annotation_has_value = False
-    class_result = None
-    method_result = None
+  def HasCurrentClass(self):
+    return bool(self._class_result)
 
-    for line in proguard_output:
-      line = line.strip('\r\n')
+  def SetSuperClass(self, superclass):
+    assert self.HasCurrentClass()
+    self._class_result['superclass'] = superclass
 
-      m = _PROGUARD_CLASS_RE.match(line)
+  def InitMethod(self, method_name):
+    self._annotation_stack = []
+    if method_name:
+      self._method_result = {
+        'method': method_name,
+        'annotations': {},
+      }
+      self._class_result['methods'].append(self._method_result)
+    else:
+      self._method_result = None
+
+  def InitAnnotation(self, annotation, depth):
+    if not self._annotation_stack:
+      # Add a fake parent element comprising 'annotations' dictionary,
+      # so we can work uniformly with both top-level and nested annotations.
+      annotations = _AnnotationElement(
+        '<<<top level>>>', _ELEMENT_ANNOTATION, depth - 1)
+      if self._method_result:
+        annotations.ref = self._method_result['annotations']
+      else:
+        annotations.ref = self._class_result['annotations']
+      self._annotation_stack = [annotations]
+    self._BacktrackAnnotationStack(depth)
+    if not self.HasCurrentAnnotation():
+      self._annotation_stack.append(
+        _AnnotationElement(annotation, _ELEMENT_ANNOTATION, depth))
+    self._CreateAnnotationPlaceHolder(self._LAZY_INITIAL_VALUES)
+
+  def HasCurrentAnnotation(self):
+    return len(self._annotation_stack) > 1
+
+  def InitAnnotationField(self, field, field_type, depth):
+    self._BacktrackAnnotationStack(depth)
+    # Create the parent representation, if needed. E.g. annotations
+    # are represented with `None`, not with `{}` until they receive the first
+    # field.
+    self._CreateAnnotationPlaceHolder(self._INITIAL_VALUES)
+    if self._annotation_stack[-1].ftype == _ELEMENT_ARRAY:
+      # Nested arrays are not allowed in annotations.
+      assert not field_type == _ELEMENT_ARRAY
+      # Use array index instead of bogus field name.
+      field = len(self._annotation_stack[-1].ref)
+    self._annotation_stack.append(_AnnotationElement(field, field_type, depth))
+    self._CreateAnnotationPlaceHolder(self._LAZY_INITIAL_VALUES)
+
+  def UpdateCurrentAnnotationFieldValue(self, value, depth):
+    self._BacktrackAnnotationStack(depth)
+    self._InitOrUpdateCurrentField(value)
+
+  def _CreateAnnotationPlaceHolder(self, constructors):
+    assert self.HasCurrentAnnotation()
+    field = self._annotation_stack[-1]
+    if field.ref is None:
+      field.ref = constructors[field.ftype]()
+      self._InitOrUpdateCurrentField(field.ref)
+
+  def _BacktrackAnnotationStack(self, depth):
+    stack = self._annotation_stack
+    while len(stack) > 0 and stack[-1].depth >= depth:
+      stack.pop()
+
+  def _InitOrUpdateCurrentField(self, value):
+    assert self.HasCurrentAnnotation()
+    parent = self._annotation_stack[-2]
+    assert not parent.ref is None
+    # There can be no nested constant element values.
+    assert parent.ftype in [_ELEMENT_ARRAY, _ELEMENT_ANNOTATION]
+    field = self._annotation_stack[-1]
+    if type(value) is str and not field.ftype == _ELEMENT_PRIMITIVE:
+      # The value comes from the output parser via
+      # UpdateCurrentAnnotationFieldValue, and should be a value of a constant
+      # element. If it isn't, just skip it.
+      return
+    if parent.ftype == _ELEMENT_ARRAY and field.name >= len(parent.ref):
+      parent.ref.append(value)
+    else:
+      parent.ref[field.name] = value
+
+
+def _GetDepth(prefix):
+  return len(prefix) // _PROGUARD_INDENT_WIDTH
+
+def Parse(proguard_output):
+  results = {
+    'classes': [],
+  }
+
+  state = _ParseState()
+
+  for line in proguard_output:
+    line = line.strip('\r\n')
+
+    m = _PROGUARD_CLASS_RE.match(line)
+    if m:
+      results['classes'].append(
+        state.CreateAndInitClass(m.group(1).replace('/', '.')))
+      continue
+
+    if not state.HasCurrentClass():
+      continue
+
+    m = _PROGUARD_SUPERCLASS_RE.match(line)
+    if m:
+      state.SetSuperClass(m.group(1).replace('/', '.'))
+      continue
+
+    m = _PROGUARD_SECTION_RE.match(line)
+    if m:
+      state.ResetPerSection(m.group(1))
+      continue
+
+    m = _PROGUARD_METHOD_RE.match(line)
+    if m:
+      state.InitMethod(m.group(1))
+      continue
+
+    if not state.ParseAnnotations():
+      continue
+
+    m = _PROGUARD_ANNOTATION_RE.match(line)
+    if m:
+      # Ignore the annotation package.
+      state.InitAnnotation(m.group(2).split('/')[-1], _GetDepth(m.group(1)))
+      continue
+
+    if state.HasCurrentAnnotation():
+      m = None
+      for (element_type, element_re) in _PROGUARD_ELEMENT_RES:
+        m = element_re.match(line)
+        if m:
+          state.InitAnnotationField(
+            m.group(2), element_type, _GetDepth(m.group(1)))
+          break
       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)
+      m = _PROGUARD_ANNOTATION_VALUE_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
+        state.UpdateCurrentAnnotationFieldValue(
+          m.group(2), _GetDepth(m.group(1)))
 
   return results
-
diff --git a/build/android/pylib/utils/proguard_test.py b/build/android/pylib/utils/proguard_test.py
new file mode 100644
index 0000000..497e12d
--- /dev/null
+++ b/build/android/pylib/utils/proguard_test.py
@@ -0,0 +1,490 @@
+# Copyright 2014 The Chromium 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.utils import proguard
+
+class TestParse(unittest.TestCase):
+
+  def setUp(self):
+    self.maxDiff = None
+
+  def testClass(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       '  Superclass: java/lang/Object'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': 'java.lang.Object',
+          'annotations': {},
+          'methods': []
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testMethod(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Methods (count = 1):',
+       '- Method:       <init>()V'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {},
+          'methods': [
+            {
+              'method': '<init>',
+              'annotations': {}
+            }
+          ]
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testClassAnnotation(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Class file attributes (count = 3):',
+       '  - Annotation [Lorg/example/Annotation;]:',
+       '  - Annotation [Lorg/example/AnnotationWithValue;]:',
+       '    - Constant element value [attr \'13\']',
+       '      - Utf8 [val]',
+       '  - Annotation [Lorg/example/AnnotationWithTwoValues;]:',
+       '    - Constant element value [attr1 \'13\']',
+       '      - Utf8 [val1]',
+       '    - Constant element value [attr2 \'13\']',
+       '      - Utf8 [val2]'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {
+            'Annotation': None,
+            'AnnotationWithValue': {'attr': 'val'},
+            'AnnotationWithTwoValues': {'attr1': 'val1', 'attr2': 'val2'}
+          },
+          'methods': []
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testClassAnnotationWithArrays(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Class file attributes (count = 3):',
+       '  - Annotation [Lorg/example/AnnotationWithEmptyArray;]:',
+       '    - Array element value [arrayAttr]:',
+       '  - Annotation [Lorg/example/AnnotationWithOneElemArray;]:',
+       '    - Array element value [arrayAttr]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val]',
+       '  - Annotation [Lorg/example/AnnotationWithTwoElemArray;]:',
+       '    - Array element value [arrayAttr]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val1]',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val2]'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {
+            'AnnotationWithEmptyArray': {'arrayAttr': []},
+            'AnnotationWithOneElemArray': {'arrayAttr': ['val']},
+            'AnnotationWithTwoElemArray': {'arrayAttr': ['val1', 'val2']}
+          },
+          'methods': []
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testNestedClassAnnotations(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Class file attributes (count = 1):',
+       '  - Annotation [Lorg/example/OuterAnnotation;]:',
+       '    - Constant element value [outerAttr \'13\']',
+       '      - Utf8 [outerVal]',
+       '    - Array element value [outerArr]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [outerArrVal1]',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [outerArrVal2]',
+       '    - Annotation element value [emptyAnn]:',
+       '      - Annotation [Lorg/example/EmptyAnnotation;]:',
+       '    - Annotation element value [ann]:',
+       '      - Annotation [Lorg/example/InnerAnnotation;]:',
+       '        - Constant element value [innerAttr \'13\']',
+       '          - Utf8 [innerVal]',
+       '        - Array element value [innerArr]:',
+       '          - Constant element value [(default) \'13\']',
+       '            - Utf8 [innerArrVal1]',
+       '          - Constant element value [(default) \'13\']',
+       '            - Utf8 [innerArrVal2]',
+       '        - Annotation element value [emptyInnerAnn]:',
+       '          - Annotation [Lorg/example/EmptyAnnotation;]:'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {
+            'OuterAnnotation': {
+              'outerAttr': 'outerVal',
+              'outerArr': ['outerArrVal1', 'outerArrVal2'],
+              'emptyAnn': None,
+              'ann': {
+                'innerAttr': 'innerVal',
+                'innerArr': ['innerArrVal1', 'innerArrVal2'],
+                'emptyInnerAnn': None
+              }
+            }
+          },
+          'methods': []
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testClassArraysOfAnnotations(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Class file attributes (count = 1):',
+       '   - Annotation [Lorg/example/OuterAnnotation;]:',
+       '     - Array element value [arrayWithEmptyAnnotations]:',
+       '       - Annotation element value [(default)]:',
+       '         - Annotation [Lorg/example/EmptyAnnotation;]:',
+       '       - Annotation element value [(default)]:',
+       '         - Annotation [Lorg/example/EmptyAnnotation;]:',
+       '     - Array element value [outerArray]:',
+       '       - Annotation element value [(default)]:',
+       '         - Annotation [Lorg/example/InnerAnnotation;]:',
+       '           - Constant element value [innerAttr \'115\']',
+       '             - Utf8 [innerVal]',
+       '           - Array element value [arguments]:',
+       '             - Annotation element value [(default)]:',
+       '               - Annotation [Lorg/example/InnerAnnotation$Argument;]:',
+       '                 - Constant element value [arg1Attr \'115\']',
+       '                   - Utf8 [arg1Val]',
+       '                 - Array element value [arg1Array]:',
+       '                   - Constant element value [(default) \'73\']',
+       '                     - Integer [11]',
+       '                   - Constant element value [(default) \'73\']',
+       '                     - Integer [12]',
+       '             - Annotation element value [(default)]:',
+       '               - Annotation [Lorg/example/InnerAnnotation$Argument;]:',
+       '                 - Constant element value [arg2Attr \'115\']',
+       '                   - Utf8 [arg2Val]',
+       '                 - Array element value [arg2Array]:',
+       '                   - Constant element value [(default) \'73\']',
+       '                     - Integer [21]',
+       '                   - Constant element value [(default) \'73\']',
+       '                     - Integer [22]'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {
+            'OuterAnnotation': {
+              'arrayWithEmptyAnnotations': [None, None],
+              'outerArray': [
+                {
+                  'innerAttr': 'innerVal',
+                  'arguments': [
+                    {'arg1Attr': 'arg1Val', 'arg1Array': ['11', '12']},
+                    {'arg2Attr': 'arg2Val', 'arg2Array': ['21', '22']}
+                  ]
+                }
+              ]
+            }
+          },
+          'methods': []
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testReadFullClassFileAttributes(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Class file attributes (count = 3):',
+       '  - Source file attribute:',
+       '    - Utf8 [Class.java]',
+       '  - Runtime visible annotations attribute:',
+       '    - Annotation [Lorg/example/IntValueAnnotation;]:',
+       '      - Constant element value [value \'73\']',
+       '        - Integer [19]',
+       '  - Inner classes attribute (count = 1)',
+       '    - InnerClassesInfo:',
+       '      Access flags:  0x9 = public static',
+       '      - Class [org/example/Class1]',
+       '      - Class [org/example/Class2]',
+       '      - Utf8 [OnPageFinishedHelper]'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {
+            'IntValueAnnotation': {
+              'value': '19',
+            }
+          },
+          'methods': []
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testMethodAnnotation(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Methods (count = 1):',
+       '- Method:       Test()V',
+       '  - Annotation [Lorg/example/Annotation;]:',
+       '  - Annotation [Lorg/example/AnnotationWithValue;]:',
+       '    - Constant element value [attr \'13\']',
+       '      - Utf8 [val]',
+       '  - Annotation [Lorg/example/AnnotationWithTwoValues;]:',
+       '    - Constant element value [attr1 \'13\']',
+       '      - Utf8 [val1]',
+       '    - Constant element value [attr2 \'13\']',
+       '      - Utf8 [val2]'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {},
+          'methods': [
+            {
+              'method': 'Test',
+              'annotations': {
+                'Annotation': None,
+                'AnnotationWithValue': {'attr': 'val'},
+                'AnnotationWithTwoValues': {'attr1': 'val1', 'attr2': 'val2'}
+              },
+            }
+          ]
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testMethodAnnotationWithArrays(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Methods (count = 1):',
+       '- Method:       Test()V',
+       '  - Annotation [Lorg/example/AnnotationWithEmptyArray;]:',
+       '    - Array element value [arrayAttr]:',
+       '  - Annotation [Lorg/example/AnnotationWithOneElemArray;]:',
+       '    - Array element value [arrayAttr]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val]',
+       '  - Annotation [Lorg/example/AnnotationWithTwoElemArray;]:',
+       '    - Array element value [arrayAttr]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val1]',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val2]'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {},
+          'methods': [
+            {
+              'method': 'Test',
+              'annotations': {
+                'AnnotationWithEmptyArray': {'arrayAttr': []},
+                'AnnotationWithOneElemArray': {'arrayAttr': ['val']},
+                'AnnotationWithTwoElemArray': {'arrayAttr': ['val1', 'val2']}
+              },
+            }
+          ]
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testMethodAnnotationWithPrimitivesAndArrays(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Methods (count = 1):',
+       '- Method:       Test()V',
+       '  - Annotation [Lorg/example/AnnotationPrimitiveThenArray;]:',
+       '    - Constant element value [attr \'13\']',
+       '      - Utf8 [val]',
+       '    - Array element value [arrayAttr]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val]',
+       '  - Annotation [Lorg/example/AnnotationArrayThenPrimitive;]:',
+       '    - Array element value [arrayAttr]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val]',
+       '    - Constant element value [attr \'13\']',
+       '      - Utf8 [val]',
+       '  - Annotation [Lorg/example/AnnotationTwoArrays;]:',
+       '    - Array element value [arrayAttr1]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val1]',
+       '    - Array element value [arrayAttr2]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [val2]'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {},
+          'methods': [
+            {
+              'method': 'Test',
+              'annotations': {
+                'AnnotationPrimitiveThenArray': {'attr': 'val',
+                                                 'arrayAttr': ['val']},
+                'AnnotationArrayThenPrimitive': {'arrayAttr': ['val'],
+                                                 'attr': 'val'},
+                'AnnotationTwoArrays': {'arrayAttr1': ['val1'],
+                                        'arrayAttr2': ['val2']}
+              },
+            }
+          ]
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testNestedMethodAnnotations(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Methods (count = 1):',
+       '- Method:       Test()V',
+       '  - Annotation [Lorg/example/OuterAnnotation;]:',
+       '    - Constant element value [outerAttr \'13\']',
+       '      - Utf8 [outerVal]',
+       '    - Array element value [outerArr]:',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [outerArrVal1]',
+       '      - Constant element value [(default) \'13\']',
+       '        - Utf8 [outerArrVal2]',
+       '    - Annotation element value [emptyAnn]:',
+       '      - Annotation [Lorg/example/EmptyAnnotation;]:',
+       '    - Annotation element value [ann]:',
+       '      - Annotation [Lorg/example/InnerAnnotation;]:',
+       '        - Constant element value [innerAttr \'13\']',
+       '          - Utf8 [innerVal]',
+       '        - Array element value [innerArr]:',
+       '          - Constant element value [(default) \'13\']',
+       '            - Utf8 [innerArrVal1]',
+       '          - Constant element value [(default) \'13\']',
+       '            - Utf8 [innerArrVal2]',
+       '        - Annotation element value [emptyInnerAnn]:',
+       '          - Annotation [Lorg/example/EmptyAnnotation;]:'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {},
+          'methods': [
+            {
+              'method': 'Test',
+              'annotations': {
+                'OuterAnnotation': {
+                  'outerAttr': 'outerVal',
+                  'outerArr': ['outerArrVal1', 'outerArrVal2'],
+                  'emptyAnn': None,
+                  'ann': {
+                    'innerAttr': 'innerVal',
+                    'innerArr': ['innerArrVal1', 'innerArrVal2'],
+                    'emptyInnerAnn': None
+                  }
+                }
+              },
+            }
+          ]
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
+
+  def testMethodArraysOfAnnotations(self):
+    actual = proguard.Parse(
+      ['- Program class: org/example/Test',
+       'Methods (count = 1):',
+       '- Method:       Test()V',
+       '   - Annotation [Lorg/example/OuterAnnotation;]:',
+       '     - Array element value [arrayWithEmptyAnnotations]:',
+       '       - Annotation element value [(default)]:',
+       '         - Annotation [Lorg/example/EmptyAnnotation;]:',
+       '       - Annotation element value [(default)]:',
+       '         - Annotation [Lorg/example/EmptyAnnotation;]:',
+       '     - Array element value [outerArray]:',
+       '       - Annotation element value [(default)]:',
+       '         - Annotation [Lorg/example/InnerAnnotation;]:',
+       '           - Constant element value [innerAttr \'115\']',
+       '             - Utf8 [innerVal]',
+       '           - Array element value [arguments]:',
+       '             - Annotation element value [(default)]:',
+       '               - Annotation [Lorg/example/InnerAnnotation$Argument;]:',
+       '                 - Constant element value [arg1Attr \'115\']',
+       '                   - Utf8 [arg1Val]',
+       '                 - Array element value [arg1Array]:',
+       '                   - Constant element value [(default) \'73\']',
+       '                     - Integer [11]',
+       '                   - Constant element value [(default) \'73\']',
+       '                     - Integer [12]',
+       '             - Annotation element value [(default)]:',
+       '               - Annotation [Lorg/example/InnerAnnotation$Argument;]:',
+       '                 - Constant element value [arg2Attr \'115\']',
+       '                   - Utf8 [arg2Val]',
+       '                 - Array element value [arg2Array]:',
+       '                   - Constant element value [(default) \'73\']',
+       '                     - Integer [21]',
+       '                   - Constant element value [(default) \'73\']',
+       '                     - Integer [22]'])
+    expected = {
+      'classes': [
+        {
+          'class': 'org.example.Test',
+          'superclass': '',
+          'annotations': {},
+          'methods': [
+            {
+              'method': 'Test',
+              'annotations': {
+                'OuterAnnotation': {
+                  'arrayWithEmptyAnnotations': [None, None],
+                  'outerArray': [
+                    {
+                      'innerAttr': 'innerVal',
+                      'arguments': [
+                        {'arg1Attr': 'arg1Val', 'arg1Array': ['11', '12']},
+                        {'arg2Attr': 'arg2Val', 'arg2Array': ['21', '22']}
+                      ]
+                    }
+                  ]
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+    self.assertEquals(expected, actual)
diff --git a/build/android/pylib/utils/repo_utils.py b/build/android/pylib/utils/repo_utils.py
index e0c7d2c..5a0efa8 100644
--- a/build/android/pylib/utils/repo_utils.py
+++ b/build/android/pylib/utils/repo_utils.py
@@ -2,7 +2,7 @@
 # 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
+from devil.utils import cmd_helper
 
 
 def GetGitHeadSHA1(in_directory):
diff --git a/build/android/pylib/utils/reraiser_thread.py b/build/android/pylib/utils/reraiser_thread.py
index 0ec16b1..828cd2b 100644
--- a/build/android/pylib/utils/reraiser_thread.py
+++ b/build/android/pylib/utils/reraiser_thread.py
@@ -1,158 +1,8 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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]
-
+from devil.utils.reraiser_thread import *
diff --git a/build/android/pylib/utils/run_tests_helper.py b/build/android/pylib/utils/run_tests_helper.py
index 43f654d..5c48668 100644
--- a/build/android/pylib/utils/run_tests_helper.py
+++ b/build/android/pylib/utils/run_tests_helper.py
@@ -1,44 +1,8 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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."""
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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)
+from devil.utils.run_tests_helper import *
diff --git a/build/android/pylib/utils/test_environment.py b/build/android/pylib/utils/test_environment.py
index e78eb5c..2ba96af 100644
--- a/build/android/pylib/utils/test_environment.py
+++ b/build/android/pylib/utils/test_environment.py
@@ -6,8 +6,8 @@
 import psutil
 import signal
 
-from pylib.device import device_errors
-from pylib.device import device_utils
+from devil.android import device_errors
+from devil.android import device_utils
 
 
 def _KillWebServers():
@@ -21,27 +21,31 @@
           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)
+        except Exception: # pylint: disable=broad-except
+          logging.exception('Failed killing %s %s', server, p.pid)
     for p in signalled:
       try:
         p.wait(1)
-      except Exception as e:
-        logging.warning('Failed waiting for %s to die. %s', p.pid, e)
+      except Exception: # pylint: disable=broad-except
+        logging.exception('Failed waiting for %s to die.', p.pid)
 
 
-def CleanupLeftoverProcesses():
-  """Clean up the test environment, restarting fresh adb and HTTP daemons."""
+def CleanupLeftoverProcesses(devices):
+  """Clean up the test environment, restarting fresh adb and HTTP daemons.
+
+  Args:
+    devices: The devices to clean.
+  """
   _KillWebServers()
   device_utils.RestartServer()
 
   def cleanup_device(d):
-    d.old_interface.RestartAdbdOnDevice()
+    d.RestartAdbd()
     try:
       d.EnableRoot()
-    except device_errors.CommandFailedError as e:
-      logging.error(str(e))
+    except device_errors.CommandFailedError:
+      logging.exception('Failed to enable root')
     d.WaitUntilFullyBooted()
 
-  device_utils.DeviceUtils.parallel().pMap(cleanup_device)
+  device_utils.DeviceUtils.parallel(devices).pMap(cleanup_device)
 
diff --git a/build/android/pylib/utils/time_profile.py b/build/android/pylib/utils/time_profile.py
index 45da7ff..094799c 100644
--- a/build/android/pylib/utils/time_profile.py
+++ b/build/android/pylib/utils/time_profile.py
@@ -9,18 +9,37 @@
 class TimeProfile(object):
   """Class for simple profiling of action, with logging of cost."""
 
-  def __init__(self, description):
+  def __init__(self, description='operation'):
     self._starttime = None
+    self._endtime = None
     self._description = description
     self.Start()
 
   def Start(self):
     self._starttime = time.time()
+    self._endtime = None
 
-  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
+  def GetDelta(self):
+    """Returns the rounded delta.
+
+    Also stops the timer if Stop() has not already been called.
+    """
+    if self._endtime is None:
+      self.Stop(log=False)
+    delta = self._endtime - self._starttime
+    delta = round(delta, 2) if delta < 10 else round(delta, 1)
+    return delta
+
+  def LogResult(self):
+    """Logs the result."""
+    logging.info('%s seconds to perform %s', self.GetDelta(), self._description)
+
+  def Stop(self, log=True):
+    """Stop profiling.
+
+    Args:
+      log: Log the delta (defaults to true).
+    """
+    self._endtime = time.time()
+    if log:
+      self.LogResult()
diff --git a/build/android/pylib/utils/timeout_retry.py b/build/android/pylib/utils/timeout_retry.py
index 61f7c70..e566f45 100644
--- a/build/android/pylib/utils/timeout_retry.py
+++ b/build/android/pylib/utils/timeout_retry.py
@@ -1,167 +1,8 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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
+from devil.utils.timeout_retry import *
diff --git a/build/android/pylib/utils/timeout_retry_unittest.py b/build/android/pylib/utils/timeout_retry_unittest.py
deleted file mode 100644
index dc36c42..0000000
--- a/build/android/pylib/utils/timeout_retry_unittest.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2013 The Chromium 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
index 2f4c464..967794c 100644
--- a/build/android/pylib/utils/watchdog_timer.py
+++ b/build/android/pylib/utils/watchdog_timer.py
@@ -1,47 +1,8 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium 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."""
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-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
+from devil.utils.watchdog_timer import *
diff --git a/build/android/pylib/utils/zip_utils.py b/build/android/pylib/utils/zip_utils.py
index d799463..007b34b 100644
--- a/build/android/pylib/utils/zip_utils.py
+++ b/build/android/pylib/utils/zip_utils.py
@@ -2,30 +2,7 @@
 # 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
+# pylint: disable=unused-wildcard-import
+# pylint: disable=wildcard-import
 
-
-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)
-
+from devil.utils.zip_utils import *
diff --git a/build/android/pylib/valgrind_tools.py b/build/android/pylib/valgrind_tools.py
index 99719d0..8142893 100644
--- a/build/android/pylib/valgrind_tools.py
+++ b/build/android/pylib/valgrind_tools.py
@@ -2,24 +2,6 @@
 # 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
@@ -28,8 +10,9 @@
 import subprocess
 import sys
 
+from devil.android import device_errors
+from devil.android.valgrind_tools import base_tool
 from pylib.constants import DIR_SOURCE_ROOT
-from pylib.device import device_errors
 
 
 def SetChromeTimeoutScale(device, scale):
@@ -42,56 +25,8 @@
     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):
+class AddressSanitizerTool(base_tool.BaseTool):
   """AddressSanitizer tool."""
 
   WRAPPER_NAME = '/system/bin/asanwrapper'
@@ -103,10 +38,6 @@
   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):
@@ -154,7 +85,7 @@
     return 20.0
 
 
-class ValgrindTool(BaseTool):
+class ValgrindTool(base_tool.BaseTool):
   """Base abstract class for Valgrind tools."""
 
   VG_DIR = '/data/local/tmp/valgrind'
@@ -274,7 +205,7 @@
     A tool for the specified tool_name.
   """
   if not tool_name:
-    return BaseTool()
+    return base_tool.BaseTool()
 
   ctor = TOOL_REGISTRY.get(tool_name)
   if ctor:
diff --git a/build/android/pylintrc b/build/android/pylintrc
new file mode 100644
index 0000000..9c2ab5a
--- /dev/null
+++ b/build/android/pylintrc
@@ -0,0 +1,11 @@
+[MESSAGES CONTROL]
+
+disable=abstract-class-not-used,bad-continuation,bad-indentation,duplicate-code,fixme,invalid-name,locally-disabled,locally-enabled,missing-docstring,star-args,too-few-public-methods,too-many-arguments,too-many-branches,too-many-instance-attributes,too-many-lines,too-many-locals,too-many-public-methods,too-many-statements,
+
+[REPORTS]
+
+reports=no
+
+[VARIABLES]
+
+dummy-variables-rgx=^_.*$|dummy
diff --git a/build/android/rezip.gyp b/build/android/rezip.gyp
index 1115177..dcb71a1 100644
--- a/build/android/rezip.gyp
+++ b/build/android/rezip.gyp
@@ -33,7 +33,6 @@
           '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/RezipApk.java b/build/android/rezip/RezipApk.java
index b4285cd..43d7544 100644
--- a/build/android/rezip/RezipApk.java
+++ b/build/android/rezip/RezipApk.java
@@ -323,7 +323,7 @@
                     throw new UnsupportedOperationException(
                             "Found more than one library\n"
                             + "Multiple libraries are not supported for APKs that use "
-                            + "'load_library_from_zip_file'.\n"
+                            + "'load_library_from_zip'.\n"
                             + "See crbug/388223.\n"
                             + "Note, check that your build is clean.\n"
                             + "An unclean build can incorrectly incorporate old "
diff --git a/build/android/screenshot.py b/build/android/screenshot.py
index 097739f..839fb55 100755
--- a/build/android/screenshot.py
+++ b/build/android/screenshot.py
@@ -11,9 +11,10 @@
 import os
 import sys
 
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_utils
 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))
@@ -26,7 +27,8 @@
 
 
 def _CaptureVideo(device, host_file, options):
-  size = tuple(map(int, options.size.split('x'))) if options.size else None
+  size = (tuple(int(i) for i in options.size.split('x')) if options.size
+          else None)
   recorder = screenshot.VideoRecorder(device,
                                       megabits_per_second=options.bitrate,
                                       size=size,
@@ -47,6 +49,7 @@
                                  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('--blacklist-file', help='Device blacklist JSON file.')
   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.',
@@ -73,7 +76,11 @@
   if options.verbose:
     logging.getLogger().setLevel(logging.DEBUG)
 
-  devices = device_utils.DeviceUtils.HealthyDevices()
+  blacklist = (device_blacklist.Blacklist(options.blacklist_file)
+               if options.blacklist_file
+               else None)
+
+  devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
   if options.device:
     device = next((d for d in devices if d == options.device), None)
     if not device:
diff --git a/build/android/setup.gyp b/build/android/setup.gyp
index b3c3422..419ed98 100644
--- a/build/android/setup.gyp
+++ b/build/android/setup.gyp
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 {
   'conditions': [
-    ['component == "shared_library"', {
+    ['android_must_copy_system_libraries == 1', {
       'targets': [
         {
           # These libraries from the Android ndk are required to be packaged with
@@ -77,6 +77,35 @@
         },
       ],
     }, # build_output_dirs
+    {
+      'target_name': 'sun_tools_java',
+      'type': 'none',
+      'variables': {
+        'found_jar_path': '<(PRODUCT_DIR)/sun_tools_java/tools.jar',
+        'jar_path': '<(found_jar_path)',
+      },
+      'includes': [
+        '../../build/host_prebuilt_jar.gypi',
+      ],
+      'actions': [
+        {
+          'action_name': 'find_sun_tools_jar',
+          'variables' : {
+          },
+          'inputs' : [
+            'gyp/find_sun_tools_jar.py',
+            'gyp/util/build_utils.py',
+          ],
+          'outputs': [
+            '<(found_jar_path)',
+          ],
+          'action': [
+            'python', 'gyp/find_sun_tools_jar.py',
+            '--output', '<(found_jar_path)',
+          ],
+        },
+      ],
+    }, # sun_tools_java
   ]
 }
 
diff --git a/build/android/strip_native_libraries.gypi b/build/android/strip_native_libraries.gypi
index bdffcfd..be8a5cb 100644
--- a/build/android/strip_native_libraries.gypi
+++ b/build/android/strip_native_libraries.gypi
@@ -35,7 +35,7 @@
     '<(stamp)',
   ],
   'conditions': [
-    ['component == "shared_library"', {
+    ['android_must_copy_system_libraries == 1', {
       # 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.
diff --git a/build/android/symbolize.py b/build/android/symbolize.py
index 56d3b19..acd4e51 100755
--- a/build/android/symbolize.py
+++ b/build/android/symbolize.py
@@ -55,6 +55,7 @@
       # 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.
+      # pylint: disable=no-member
       sym = symbol.SymbolInformation(lib, addr, False)[0][0]
 
       if not sym:
diff --git a/build/android/test_runner.gypi b/build/android/test_runner.gypi
new file mode 100644
index 0000000..f571888
--- /dev/null
+++ b/build/android/test_runner.gypi
@@ -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.
+
+# Generates a script in the output bin directory which runs the test
+# target using the test runner script in build/android/pylib/test_runner.py.
+#
+# To use this, include this file in a gtest or instrumentation test target.
+# {
+#   'target_name': 'gtest',
+#   'type': 'none',
+#   'variables': {
+#     'test_type': 'gtest',  # string
+#     'test_suite_name': 'gtest_suite'  # string
+#     'isolate_file': 'path/to/gtest.isolate'  # string
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+# {
+#   'target_name': 'instrumentation_apk',
+#   'type': 'none',
+#   'variables': {
+#     'test_type': 'instrumentation',  # string
+#     'apk_name': 'TestApk'  # string
+#     'isolate_file': 'path/to/instrumentation_test.isolate'  # string
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+
+{
+  'variables': {
+    'variables': {
+      'isolate_file%': '',
+    },
+    'test_runner_args': ['--output-directory', '<(PRODUCT_DIR)'],
+    'conditions': [
+      ['test_type == "gtest"', {
+        'test_runner_args': ['--suite', '<(test_suite_name)'],
+        'script_name': 'run_<(test_suite_name)',
+      }],
+      ['test_type == "instrumentation"', {
+        'test_runner_args': [
+          '--apk-under-test', '>(tested_apk_path)',
+          '--test-apk', '>(final_apk_path)',
+        ],
+        'script_name': 'run_<(_target_name)',
+      }],
+      ['isolate_file != ""', {
+        'test_runner_args': ['--isolate-file-path', '<(isolate_file)']
+      }],
+    ],
+  },
+  'actions': [
+    {
+      'action_name': 'create_test_runner_script_<(script_name)',
+      'message': 'Creating test runner script <(script_name)',
+      'variables': {
+        'script_output_path': '<(PRODUCT_DIR)/bin/<(script_name)',
+      },
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/create_test_runner_script.py',
+      ],
+      'outputs': [
+        '<(script_output_path)'
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/create_test_runner_script.py',
+        '--script-output-path=<(script_output_path)',
+        '<(test_type)', '<@(test_runner_args)',
+      ],
+    },
+  ],
+}
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index b71f805..c4baaf1 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -8,27 +8,30 @@
 
 import argparse
 import collections
+import itertools
 import logging
 import os
-import shutil
 import signal
 import sys
 import threading
 import unittest
 
+from devil import base_error
+from devil.android import apk_helper
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.android import ports
+from devil.utils import reraiser_thread
+from devil.utils import run_tests_helper
+
 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
@@ -42,12 +45,6 @@
 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):
@@ -76,7 +73,8 @@
                            ' 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,
+  group.add_argument('--num_retries', '--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',
@@ -100,7 +98,8 @@
   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',
+  group.add_argument('--json-results-file', '--test-launcher-summary-output',
+                     dest='json_results_file',
                      help='If set, will dump results in JSON form '
                           'to specified file.')
 
@@ -156,6 +155,8 @@
   group.add_argument('--network-config', type=int,
                      help='Integer that specifies the network environment '
                           'that the tests will be run in.')
+  group.add_argument('--test-timeout', type=int,
+                     help='Test run timeout in seconds.')
 
   device_os_group = group.add_mutually_exclusive_group()
   device_os_group.add_argument('--remote-device-minimum-os',
@@ -186,20 +187,23 @@
   group.add_argument('-d', '--device', dest='test_device',
                      help=('Target device for the test suite '
                            'to run on.'))
+  group.add_argument('--blacklist-file', help='Device blacklist file.')
+  group.add_argument('--enable-device-cache', action='store_true',
+                     help='Cache device state to disk between runs')
+  group.add_argument('--incremental-install', action='store_true',
+                     help='Use an _incremental apk.')
+  group.add_argument('--enable-concurrent-adb', action='store_true',
+                     help='Run multiple adb commands at the same time, even '
+                          'for the same device.')
 
 
 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)))
+                     help='Executable name of the test suite to run.')
   group.add_argument('--gtest_also_run_disabled_tests',
                      '--gtest-also-run-disabled-tests',
                      dest='run_disabled', action='store_true',
@@ -207,7 +211,8 @@
   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,
+  group.add_argument('-t', '--shard-timeout',
+                     dest='shard_timeout', type=int, default=60,
                      help='Timeout to wait for each test '
                           '(default: %(default)s).')
   group.add_argument('--isolate_file_path',
@@ -215,6 +220,19 @@
                      dest='isolate_file_path',
                      help='.isolate file path to override the default '
                           'path')
+  group.add_argument('--app-data-file', action='append', dest='app_data_files',
+                     help='A file path relative to the app data directory '
+                          'that should be saved to the host.')
+  group.add_argument('--app-data-file-dir',
+                     help='Host directory to which app data files will be'
+                          ' saved. Used with --app-data-file.')
+  group.add_argument('--delete-stale-data', dest='delete_stale_data',
+                     action='store_true',
+                     help='Delete stale test data on the device.')
+  group.add_argument('--repeat', '--gtest_repeat', '--gtest-repeat',
+                     dest='repeat', type=int, default=0,
+                     help='Number of times to repeat the specified set of '
+                          'tests.')
 
   filter_group = group.add_mutually_exclusive_group()
   filter_group.add_argument('-f', '--gtest_filter', '--gtest-filter',
@@ -245,6 +263,9 @@
       '-f', '--test-filter', dest='test_filter',
       help=('Test filter (if not fully qualified, will run all matches).'))
   argument_group.add_argument(
+      '--repeat', dest='repeat', type=int, default=0,
+      help='Number of times to repeat the specified set of tests.')
+  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 '
@@ -321,6 +342,10 @@
                      help=('The name of the apk containing the tests '
                            '(without the .apk extension; '
                            'e.g. "ContentShellTest").'))
+  group.add_argument('--additional-apk', action='append',
+                     dest='additional_apks', default=[],
+                     help='Additional apk that must be installed on '
+                          'the device when the tests are run')
   group.add_argument('--coverage-dir',
                      help=('Directory in which to place all generated '
                            'EMMA coverage files.'))
@@ -335,6 +360,11 @@
                      dest='isolate_file_path',
                      help='.isolate file path to override the default '
                           'path')
+  group.add_argument('--delete-stale-data', dest='delete_stale_data',
+                     action='store_true',
+                     help='Delete stale test data on the device.')
+  group.add_argument('--timeout-scale', type=float,
+                     help='Factor by which timeouts should be scaled.')
 
   AddCommonOptions(parser)
   AddDeviceOptions(parser)
@@ -357,14 +387,19 @@
   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)
+  if os.path.exists(args.test_apk):
+    args.test_apk_path = args.test_apk
+    args.test_apk, _ = os.path.splitext(os.path.basename(args.test_apk))
+  else:
+    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)
+      '%s.jar' % args.test_apk)
   args.test_support_apk_path = '%sSupport%s' % (
       os.path.splitext(args.test_apk_path))
 
@@ -388,8 +423,9 @@
       args.test_support_apk_path,
       args.device_flags,
       args.isolate_file_path,
-      args.set_asserts
-      )
+      args.set_asserts,
+      args.delete_stale_data,
+      args.timeout_scale)
 
 
 def AddUIAutomatorTestOptions(parser):
@@ -410,45 +446,6 @@
   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|."""
 
@@ -530,6 +527,9 @@
   group.add_argument('--app-under-test', required=True,
                      help='APK to run tests on.')
   group.add_argument(
+      '--repeat', dest='repeat', type=int, default=0,
+      help='Number of times to repeat the uirobot test.')
+  group.add_argument(
       '--minutes', default=5, type=int,
       help='Number of minutes to run uirobot test [default: %(default)s].')
 
@@ -578,6 +578,10 @@
       default='',
       help='Write out chartjson into the given file.')
   group.add_argument(
+      '--get-output-dir-archive', metavar='FILENAME',
+      help='Write the chached output directory archived by a step into the'
+      ' given ZIP file.')
+  group.add_argument(
       '--flaky-steps',
       help=('A JSON file containing steps that are flaky '
             'and will have its exit code ignored.'))
@@ -591,8 +595,16 @@
   group.add_argument(
       '--dry-run', action='store_true',
       help='Just print the steps without executing.')
+  # Uses 0.1 degrees C because that's what Android does.
+  group.add_argument(
+      '--max-battery-temp', type=int,
+      help='Only start tests when the battery is at or below the given '
+           'temperature (0.1 C)')
   group.add_argument('single_step_command', nargs='*', action=SingleStepAction,
                      help='If --single-step is specified, the command to run.')
+  group.add_argument('--min-battery-level', type=int,
+                     help='Only starts tests when the battery is charged above '
+                          'given level.')
   AddCommonOptions(parser)
   AddDeviceOptions(parser)
 
@@ -615,7 +627,8 @@
       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)
+      args.output_chartjson_data, args.get_output_dir_archive,
+      args.max_battery_temp, args.min_battery_level)
 
 
 def AddPythonTestOptions(parser):
@@ -627,41 +640,6 @@
   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)
-
-  return exit_code
-
-
 def _RunLinkerTests(args, devices):
   """Subcommand of RunTestsCommands which runs linker tests."""
   runner_factory, tests = linker_setup.Setup(args, devices)
@@ -676,14 +654,14 @@
       test_package='ChromiumLinkerTest')
 
   if args.json_results_file:
-    json_results.GenerateJsonResultsFile(results, 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)))
+  logging.info('_RunInstrumentationTests(%s, %s)', str(args), str(devices))
 
   instrumentation_options = ProcessInstrumentationOptions(args)
 
@@ -695,64 +673,52 @@
   exit_code = 0
 
   if args.run_java_tests:
-    runner_factory, tests = instrumentation_setup.Setup(
+    java_runner_factory, java_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)
+  else:
+    java_runner_factory = None
+    java_tests = None
 
   if args.run_python_tests:
-    runner_factory, tests = host_driven_setup.InstrumentationSetup(
+    py_runner_factory, py_tests = host_driven_setup.InstrumentationSetup(
         args.host_driven_root, args.official_build,
         instrumentation_options)
+  else:
+    py_runner_factory = None
+    py_tests = None
 
-    if tests:
+  results = []
+  repetitions = (xrange(args.repeat + 1) if args.repeat >= 0
+                 else itertools.count())
+  for _ in repetitions:
+    iteration_results = base_test_result.TestRunResults()
+    if java_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)
+          java_tests, java_runner_factory, devices, shard=True,
+          test_timeout=None, num_retries=args.num_retries)
+      iteration_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)
+    if py_tests:
+      test_results, test_exit_code = test_dispatcher.RunTests(
+          py_tests, py_runner_factory, devices, shard=True, test_timeout=None,
+          num_retries=args.num_retries)
+      iteration_results.AddTestRunResults(test_results)
 
-  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)
+      # Only allow exit code escalation
+      if test_exit_code and exit_code != constants.ERROR_EXIT_CODE:
+        exit_code = test_exit_code
 
-  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)
+    results.append(iteration_results)
+    report_results.LogFull(
+        results=iteration_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)
@@ -771,7 +737,7 @@
       test_package=args.test_suite)
 
   if args.json_results_file:
-    json_results.GenerateJsonResultsFile(results, args.json_results_file)
+    json_results.GenerateJsonResultsFile([results], args.json_results_file)
 
   return exit_code
 
@@ -792,12 +758,12 @@
       test_package='Monkey')
 
   if args.json_results_file:
-    json_results.GenerateJsonResultsFile(results, args.json_results_file)
+    json_results.GenerateJsonResultsFile([results], args.json_results_file)
 
   return exit_code
 
 
-def _RunPerfTests(args):
+def _RunPerfTests(args, active_devices):
   """Subcommand of RunTestsCommands which runs perf tests."""
   perf_options = ProcessPerfTestOptions(args)
 
@@ -809,9 +775,11 @@
   # 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)
+        perf_options.print_step, perf_options.output_chartjson_data,
+        perf_options.get_output_dir_archive)
 
-  runner_factory, tests, devices = perf_setup.Setup(perf_options)
+  runner_factory, tests, devices = perf_setup.Setup(
+      perf_options, active_devices)
 
   # shard=False means that each device will get the full list of tests
   # and then each one will decide their own affinity.
@@ -827,7 +795,7 @@
       test_package='Perf')
 
   if args.json_results_file:
-    json_results.GenerateJsonResultsFile(results, args.json_results_file)
+    json_results.GenerateJsonResultsFile([results], args.json_results_file)
 
   if perf_options.single_step:
     return perf_test_runner.PrintTestOutput('single_step')
@@ -856,16 +824,23 @@
     sys.path = sys.path[1:]
 
 
-def _GetAttachedDevices(test_device=None):
+def _GetAttachedDevices(blacklist_file, test_device, enable_cache):
   """Get all attached devices.
 
   Args:
+    blacklist_file: Path to device blacklist.
     test_device: Name of a specific device to use.
+    enable_cache: Whether to enable checksum caching.
 
   Returns:
     A list of attached devices.
   """
-  attached_devices = device_utils.DeviceUtils.HealthyDevices()
+  blacklist = (device_blacklist.Blacklist(blacklist_file)
+               if blacklist_file
+               else None)
+
+  attached_devices = device_utils.DeviceUtils.HealthyDevices(
+      blacklist, enable_device_files_cache=enable_cache)
   if test_device:
     test_device = [d for d in attached_devices if d == test_device]
     if not test_device:
@@ -880,7 +855,7 @@
     return sorted(attached_devices)
 
 
-def RunTestsCommand(args, parser):
+def RunTestsCommand(args, parser): # pylint: disable=too-many-return-statements
   """Checks test type and dispatches to the appropriate function.
 
   Args:
@@ -901,29 +876,26 @@
   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.')
 
+  def get_devices():
+    return _GetAttachedDevices(args.blacklist_file, args.test_device,
+                               args.enable_device_cache)
+
   if command == 'gtest':
-    return _RunGTests(args, devices)
+    return RunTestsInPlatformMode(args, parser)
   elif command == 'linker':
-    return _RunLinkerTests(args, devices)
+    return _RunLinkerTests(args, get_devices())
   elif command == 'instrumentation':
-    return _RunInstrumentationTests(args, devices)
-  elif command == 'uiautomator':
-    return _RunUIAutomatorTests(args, devices)
+    return _RunInstrumentationTests(args, get_devices())
   elif command == 'junit':
     return _RunJUnitTests(args)
   elif command == 'monkey':
-    return _RunMonkeyTests(args, devices)
+    return _RunMonkeyTests(args, get_devices())
   elif command == 'perf':
-    return _RunPerfTests(args)
+    return _RunPerfTests(args, get_devices())
   elif command == 'python':
     return _RunPythonTests(args)
   else:
@@ -940,30 +912,38 @@
 
 def RunTestsInPlatformMode(args, parser):
 
+  def infra_error(message):
+    parser.exit(status=constants.INFRA_EXIT_CODE, message=message)
+
   if args.command not in _SUPPORTED_IN_PLATFORM_MODE:
-    parser.error('%s is not yet supported in platform mode' % args.command)
+    infra_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 environment_factory.CreateEnvironment(args, infra_error) as env:
+    with test_instance_factory.CreateTestInstance(args, infra_error) as test:
       with test_run_factory.CreateTestRun(
-          args, env, test, parser.error) as test_run:
-        results = test_run.RunTests()
+          args, env, test, infra_error) as test_run:
+        results = []
+        repetitions = (xrange(args.repeat + 1) if args.repeat >= 0
+                       else itertools.count())
+        for _ in repetitions:
+          iteration_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 iteration_results is not None:
+            results.append(iteration_results)
+            report_results.LogFull(
+                results=iteration_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
+  return (0 if all(r.DidRunPass() for r in results)
+          else constants.ERROR_EXIT_CODE)
 
 
 CommandConfigTuple = collections.namedtuple(
@@ -976,9 +956,6 @@
     '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'),
@@ -1026,8 +1003,7 @@
     logging.exception('Error occurred.')
     if e.is_infra_error:
       return constants.INFRA_EXIT_CODE
-    else:
-      return constants.ERROR_EXIT_CODE
+    return constants.ERROR_EXIT_CODE
   except: # pylint: disable=W0702
     logging.exception('Unrecognized error occurred.')
     return constants.ERROR_EXIT_CODE
diff --git a/build/android/tests/multiple_proguards/AndroidManifest.xml b/build/android/tests/multiple_proguards/AndroidManifest.xml
deleted file mode 100644
index 1794712..0000000
--- a/build/android/tests/multiple_proguards/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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
deleted file mode 100644
index 48a5d7b..0000000
--- a/build/android/tests/multiple_proguards/multiple_proguards.gyp
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (c) 2013 The Chromium 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
deleted file mode 100644
index 95a814c..0000000
--- a/build/android/tests/multiple_proguards/proguard1.flags
+++ /dev/null
@@ -1 +0,0 @@
--dontwarn sun.misc.Unsafe
diff --git a/build/android/tests/multiple_proguards/proguard2.flags b/build/android/tests/multiple_proguards/proguard2.flags
deleted file mode 100644
index ceac62b..0000000
--- a/build/android/tests/multiple_proguards/proguard2.flags
+++ /dev/null
@@ -1 +0,0 @@
--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
deleted file mode 100644
index e138acc..0000000
--- a/build/android/tests/multiple_proguards/src/dummy/DummyActivity.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2013 The Chromium 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
deleted file mode 100644
index 2f7db71..0000000
--- a/build/android/tests/multiple_proguards/src/dummy/NativeLibraries.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014 The Chromium 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/tombstones.py b/build/android/tombstones.py
index c83a584..f1108dd 100755
--- a/build/android/tombstones.py
+++ b/build/android/tombstones.py
@@ -10,7 +10,6 @@
 # Assumes tombstone file was created with current symbols.
 
 import datetime
-import itertools
 import logging
 import multiprocessing
 import os
@@ -19,11 +18,10 @@
 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
-
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.utils import run_tests_helper
 
 _TZ_UTC = {'TZ': 'UTC'}
 
@@ -37,17 +35,22 @@
     Tuples of (tombstone filename, date time of file on device).
   """
   try:
+    if not device.PathExists('/data/tombstones', timeout=60, retries=3):
+      return
+    # TODO(perezju): Introduce a DeviceUtils.Ls() method (crbug.com/552376).
     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:
+      if 'tombstone' 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.')
+  except device_errors.CommandTimeoutError:
+    logging.exception('Timed out retrieving tombstones.')
 
 
 def _GetDeviceDateTime(device):
@@ -157,12 +160,13 @@
     logging.warning('No tombstones to resolve.')
     return
   if len(tombstones) == 1:
-    data = _ResolveTombstone(tombstones[0])
+    data = [_ResolveTombstone(tombstones[0])]
   else:
     pool = multiprocessing.Pool(processes=jobs)
     data = pool.map(_ResolveTombstone, tombstones)
-  for d in data:
-    logging.info(d)
+  for tombstone in data:
+    for line in tombstone:
+      logging.info(line)
 
 
 def _GetTombstonesForDevice(device, options):
@@ -219,6 +223,7 @@
   parser.add_option('--device',
                     help='The serial number of the device. If not specified '
                          'will use all devices.')
+  parser.add_option('--blacklist-file', help='Device blacklist JSON file.')
   parser.add_option('-a', '--all-tombstones', action='store_true',
                     help="""Resolve symbols for all tombstones, rather than just
                          the most recent""")
@@ -232,10 +237,14 @@
                          'crash stacks.')
   options, _ = parser.parse_args()
 
+  blacklist = (device_blacklist.Blacklist(options.blacklist_file)
+               if options.blacklist_file
+               else None)
+
   if options.device:
     devices = [device_utils.DeviceUtils(options.device)]
   else:
-    devices = device_utils.DeviceUtils.HealthyDevices()
+    devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
 
   # This must be done serially because strptime can hit a race condition if
   # used for the first time in a multithreaded environment.
diff --git a/build/android/update_verification.py b/build/android/update_verification.py
index dada794..bdd49f1 100755
--- a/build/android/update_verification.py
+++ b/build/android/update_verification.py
@@ -26,32 +26,28 @@
 
 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
+from devil.android import apk_helper
+from devil.android import device_blacklist
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.utils import run_tests_helper
 
-def CreateAppData(device, old_apk, app_data):
+def CreateAppData(device, old_apk, app_data, package_name):
   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)
+  logging.critical('Application data saved to %s', app_data)
 
-def TestUpdate(device, old_apk, new_apk, app_data):
+def TestUpdate(device, old_apk, new_apk, app_data, package_name):
   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)
+  device_path = device.GetApplicationPaths(package_name)
   if not device_path:
     raise Exception('Expected package %s to already be installed. '
                     'Package name might have changed!' % package_name)
@@ -66,34 +62,48 @@
       description="Script to do semi-automated upgrade testing.")
   parser.add_argument('-v', '--verbose', action='count',
                       help='Print verbose log information.')
+  parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
   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.')
+                         help='Path to apk to update from.')
   subparser.add_argument('--app-data', required=True,
-                      help='Path to where the app data backup should be '
+                         help='Path to where the app data backup should be '
                            'saved to.')
+  subparser.add_argument('--package-name',
+                         help='Chrome apk package name.')
 
   subparser = command_parsers.add_parser('test_update')
   subparser.add_argument('--old-apk', required=True,
-                      help='Path to apk to update from.')
+                         help='Path to apk to update from.')
   subparser.add_argument('--new-apk', required=True,
-                      help='Path to apk to update to.')
+                         help='Path to apk to update to.')
   subparser.add_argument('--app-data', required=True,
-                      help='Path to where the app data backup is saved.')
+                         help='Path to where the app data backup is saved.')
+  subparser.add_argument('--package-name',
+                         help='Chrome apk package name.')
 
   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))
+  blacklist = (device_blacklist.Blacklist(args.blacklist_file)
+               if args.blacklist_file
+               else None)
 
+  devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
+  if not devices:
+    raise device_errors.NoDevicesError()
+  device = devices[0]
+  logging.info('Using device %s for testing.', str(device))
+
+  package_name = (args.package_name if args.package_name
+                  else apk_helper.GetPackageName(args.old_apk))
   if args.command == 'create_app_data':
-    CreateAppData(device, args.old_apk, args.app_data)
+    CreateAppData(device, args.old_apk, args.app_data, package_name)
   elif args.command == 'test_update':
-    TestUpdate(device,  args.old_apk, args.new_apk, args.app_data)
+    TestUpdate(
+        device, args.old_apk, args.new_apk, args.app_data, package_name)
   else:
     raise Exception('Unknown test command: %s' % args.command)
 
diff --git a/build/android/v8_external_startup_data_arch_suffix.gypi b/build/android/v8_external_startup_data_arch_suffix.gypi
new file mode 100644
index 0000000..7af2443
--- /dev/null
+++ b/build/android/v8_external_startup_data_arch_suffix.gypi
@@ -0,0 +1,21 @@
+# 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.
+
+{
+  'variables': {
+    'arch_suffix': '<(arch_suffix)',
+    'variables': {
+      # This help to find out if target_arch is set to something else.
+      'arch_suffix': '<(target_arch)',
+      'conditions': [
+        ['target_arch=="arm" or target_arch=="ia32" or target_arch=="mipsel"', {
+          'arch_suffix': '32',
+        }],
+        ['target_arch=="arm64" or target_arch=="x64" or target_arch=="mips64el"', {
+          'arch_suffix':'64'
+        }],
+      ],
+    }
+  }
+}
diff --git a/build/android_sdk_extras.json b/build/android_sdk_extras.json
deleted file mode 100644
index 4562726..0000000
--- a/build/android_sdk_extras.json
+++ /dev/null
@@ -1,8 +0,0 @@
-[
-  {
-    "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_browsertest.gypi b/build/apk_browsertest.gypi
new file mode 100644
index 0000000..8cbc413
--- /dev/null
+++ b/build/apk_browsertest.gypi
@@ -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.
+
+# This file is meant to be included into a target to provide a rule
+# to build APK-based browser 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
+#     'java_in_dir': 'path/to/java/dir',
+#   },
+#   '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)/testing/android/native_test.gyp:native_test_java',
+    '<(DEPTH)/tools/android/android_tools.gyp:android_tools',
+  ],
+  'conditions': [
+    ['OS == "android"', {
+      'variables': {
+        # These are used to configure java_apk.gypi included below.
+        'test_type': 'gtest',
+        'apk_name': '<(test_suite_name)',
+        'intermediate_dir': '<(PRODUCT_DIR)/<(test_suite_name)_apk',
+        'final_apk_path': '<(intermediate_dir)/<(test_suite_name)-debug.apk',
+        'native_lib_target': 'lib<(test_suite_name)',
+        # TODO(yfriedman, cjhopman): Support managed installs for gtests.
+        'gyp_managed_install': 0,
+      },
+      'includes': [ 'java_apk.gypi', 'android/test_runner.gypi' ],
+    }],  # 'OS == "android"
+  ],  # conditions
+}
diff --git a/build/apk_test.gypi b/build/apk_test.gypi
index 3a66e3b..e0d323f 100644
--- a/build/apk_test.gypi
+++ b/build/apk_test.gypi
@@ -23,12 +23,14 @@
     '<(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)/testing/android/on_device_instrumentation.gyp:reporter_java',
     '<(DEPTH)/tools/android/android_tools.gyp:android_tools',
   ],
   'conditions': [
      ['OS == "android"', {
        'variables': {
          # These are used to configure java_apk.gypi included below.
+         'test_type': 'gtest',
          'apk_name': '<(test_suite_name)',
          'intermediate_dir': '<(PRODUCT_DIR)/<(test_suite_name)_apk',
          'final_apk_path': '<(intermediate_dir)/<(test_suite_name)-debug.apk',
@@ -37,7 +39,7 @@
          # TODO(yfriedman, cjhopman): Support managed installs for gtests.
          'gyp_managed_install': 0,
        },
-       'includes': [ 'java_apk.gypi' ],
+       'includes': [ 'java_apk.gypi', 'android/test_runner.gypi' ],
      }],  # 'OS == "android"
   ],  # conditions
 }
diff --git a/build/args/aura_android.gni b/build/args/aura_android.gni
new file mode 100644
index 0000000..725c41b
--- /dev/null
+++ b/build/args/aura_android.gni
@@ -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.
+
+# This file contains the common overrides for building Aura on Android.
+# To enable Aura on Android, import this file from your gn args:
+#
+#    import("//build/args/aura_android.gni")
+
+target_os = "android"
+
+# features.gni overrides
+enable_extensions = true
+enable_plugins = true
+
+# ui.gni overrides
+use_aura = true
+toolkit_views = true
diff --git a/build/buildflag.h b/build/buildflag.h
new file mode 100644
index 0000000..283f5bc
--- /dev/null
+++ b/build/buildflag.h
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BUILD_BUILDFLAG_H_
+#define BUILD_BUILDFLAG_H_
+
+// These macros un-mangle the names of the build flags in a way that looks
+// natural, and gives errors if the flag is not defined. Normally in the
+// preprocessor it's easy to make mistakes that interpret "you haven't done
+// the setup to know what the flag is" as "flag is off". Normally you would
+// include the generated header rather than include this file directly.
+//
+// This is for use with generated headers. See build/build_header.gni.
+
+// This dance of two macros does a concatenation of two preprocessor args using
+// ## doubly indirectly because using ## directly prevents macros in that
+// parameter from being expanded.
+#define BUILDFLAG_CAT_INDIRECT(a, b) a ## b
+#define BUILDFLAG_CAT(a, b) BUILDFLAG_CAT_INDIRECT(a, b)
+
+// Accessor for build flags.
+//
+// To test for a value, if the build file specifies:
+//
+//   ENABLE_FOO=true
+//
+// Then you would check at build-time in source code with:
+//
+//   #include "foo_flags.h"  // The header the build file specified.
+//
+//   #if BUILDFLAG(ENABLE_FOO)
+//     ...
+//   #endif
+//
+// There will no #define called ENABLE_FOO so if you accidentally test for
+// whether that is defined, it will always be negative. You can also use
+// the value in expressions:
+//
+//   const char kSpamServerName[] = BUILDFLAG(SPAM_SERVER_NAME);
+//
+// Because the flag is accessed as a preprocessor macro with (), an error
+// will be thrown if the proper header defining the internal flag value has
+// not been included.
+#define BUILDFLAG(flag) (BUILDFLAG_CAT(BUILDFLAG_INTERNAL_, flag)())
+
+#endif  // BUILD_BUILDFLAG_H_
diff --git a/build/buildflag_header.gni b/build/buildflag_header.gni
new file mode 100644
index 0000000..9054d07
--- /dev/null
+++ b/build/buildflag_header.gni
@@ -0,0 +1,138 @@
+# Copyright 2015 The Chromium 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 a header with preprocessor defines specified by the build file.
+# The GYP version of this (with instructions) is build/buildflag_header.gypi.
+#
+# The flags are converted to function-style defines with mangled names and
+# code uses an accessor macro to access the values. This is to try to
+# minimize bugs where code checks whether something is defined or not, and
+# the proper header isn't included, meaning the answer will always be silently
+# false or might vary across the code base.
+#
+# In the GN template, specify build flags in the template as a list
+# of strings that encode key/value pairs like this:
+#
+#   flags = [ "ENABLE_FOO=1", "ENABLE_BAR=$enable_bar" ]
+#
+# The GN values "true" and "false" will be mapped to 0 and 1 for boolean
+# #if flags to be expressed naturally. This means you can't directly make a
+# define that generates C++ value of true or false for use in code. If you
+# REALLY need this, you can also use the string "(true)" and "(false)" to
+# prevent the rewriting.
+
+# To check the value of the flag in C code:
+#
+#   #include "path/to/here/header_file.h"
+#
+#   #if BUILDFLAG(ENABLE_FOO)
+#   ...
+#   #endif
+#
+#   const char kSpamServerUrl[] = BUILDFLAG(SPAM_SERVER_URL);
+#
+# There will no #define called ENABLE_FOO so if you accidentally test for that
+# in an ifdef it will always be negative.
+#
+#
+# Template parameters
+#
+#   flags [required, list of strings]
+#       Flag values as described above.
+#
+#   header [required, string]
+#       File name for generated header. By default, this will go in the
+#       generated file directory for this target, and you would include it
+#       with:
+#         #include "<path_to_this_BUILD_file>/<header>"
+#
+#   header_dir [optional, string]
+#       Override the default location of the generated header. The string will
+#       be treated as a subdirectory of the root_gen_dir. For example:
+#         header_dir = "foo/bar"
+#       Then you can include the header as:
+#         #include "foo/bar/baz.h"
+#
+#   deps, public_deps, testonly, visibility
+#       Normal meaning.
+#
+#
+# Grit defines
+#
+# If one .grd file uses a flag, just add to the grit target:
+#
+#   defines = [
+#     "enable_doom_melon=$enable_doom_melon",
+#   ]
+#
+# If multiple .grd files use it, you'll want to put the defines in a .gni file
+# so it can be shared. Generally this .gni file should include all grit defines
+# for a given module (for some definition of "module"). Then do:
+#
+#   defines = ui_grit_defines
+#
+# If you forget to do this, the flag will be implicitly false in the .grd file
+# and those resources won't be compiled. You'll know because the resource
+# #define won't be generated and any code that uses it won't compile. If you
+# see a missing IDS_* string, this is probably the reason.
+#
+#
+# Example
+#
+#   buildflag_header("foo_features") {
+#     header = "foo_features.h"
+#
+#     flags = [
+#       # This uses the GN build flag enable_doom_melon as the definition.
+#       "ENABLE_DOOM_MELON=$enable_doom_melon",
+#
+#       # This force-enables the flag.
+#       "ENABLE_SPACE_LASER=true",
+#
+#       # This will expand to the quoted C string when used in source code.
+#       "SPAM_SERVER_URL=\"http://www.example.com/\"",
+#     ]
+#   }
+template("buildflag_header") {
+  action(target_name) {
+    script = "//build/write_buildflag_header.py"
+
+    if (defined(invoker.header_dir)) {
+      header_file = "${invoker.header_dir}/${invoker.header}"
+    } else {
+      # Compute the path from the root to this file.
+      header_file = rebase_path(".", "//") + "/${invoker.header}"
+    }
+
+    outputs = [
+      "$root_gen_dir/$header_file",
+    ]
+
+    # Always write --flags to the file so it's not empty. Empty will confuse GN
+    # into thinking the response file isn't used.
+    response_file_contents = [ "--flags" ]
+    if (defined(invoker.flags)) {
+      response_file_contents += invoker.flags
+    }
+
+    args = [
+      "--output",
+      header_file,  # Not rebased, Python script puts it inside gen-dir.
+      "--rulename",
+      get_label_info(":$target_name", "label_no_toolchain"),
+      "--gen-dir",
+      rebase_path(root_gen_dir, root_out_dir),
+      "--definitions",
+      "{{response_file_name}}",
+    ]
+
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "public_deps",
+                             "testonly",
+                             "visibility",
+                           ])
+  }
+}
diff --git a/build/buildflag_header.gypi b/build/buildflag_header.gypi
new file mode 100644
index 0000000..af86677
--- /dev/null
+++ b/build/buildflag_header.gypi
@@ -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.
+
+# Generates a header with preprocessor defines specified by the build file.
+#
+# The canonical documentation is in build/buildflag_header.gni. You should
+# write the GN build, get it working, and then transform it into GYP.
+#
+# In every target that uses your generated header you must include a dependency
+# on the GYP target that generates the header (this is implicit in GN).
+# Otherwise, clean builds may not necessarily create the header before the
+# source code is compiled.
+#
+# Assuming your GN code looks like this:
+#
+#   buildflag_header("foo_features") {
+#     header = "foo_features.h"
+#     flags = [
+#       "ENABLE_DOOM_MELON=$enable_doom_melon",
+#       "ENABLE_SPACE_LASER=true",
+#       "SPAM_SERVER_URL=\"http://www.example.com/\"",
+#     ]
+#   }
+#
+# Write a GYP target like this:
+#
+#  {
+#    # GN version: //foo:foo_features
+#    'target_name': 'foo_foo_features',
+#    'includes': [ '../build/buildflag_header.gypi' ],
+#    'variables': {
+#       'buildflag_header_path': 'foo/foo_features.h',
+#       'buildflag_flags': [
+#         'ENABLE_DOOM_MELON=<(enable_doom_melon)',
+#         'ENABLE_SPACE_LASER=true',
+#         'SPAM_SERVER_URL="http://www.example.com/"',
+#       ],
+#     },
+#   }
+#
+# Variables
+#
+#   target_name
+#       Base this on the GN label, replacing / and : with _ to make it globally
+#       unique.
+#
+#   buildflag_header_path
+#       This must be the full path to the header from the source root. In GN
+#       you only say "features.h" and it uses the BUILD file's path implicitly.
+#       Use the path to BUILD.gn followed by your header name to produce the
+#       same output file.
+#
+#   buildflag_flags (optional)
+#       List of the same format as GN's "flags". To expand variables, use
+#       "<(foo)" where GN would have used "$foo".
+#
+#   includes
+#       List the relative path to build/buildflag_header.gypi from the .gyp
+#       file including this code, Note: If your code is in a .gypi file in a
+#       different directory, this must be relative to the .gyp including your
+#       file.
+#
+#
+# Grit defines
+#
+# Follow the same advice as in the buildflag_header.gni, except on the grit
+# action use the variable name 'grit_additional_defines' and explicitly add a
+# '-D' in front:
+#
+#   'grit_grd_file': 'foo.grd',
+#   'grit_additional_defines': [
+#     '-D', 'enable_doom_melon=<(enable_doom_melon)',
+#    ],
+#
+# Put shared lists of defines in a .gypi.
+
+{
+  'type': 'none',
+  'hard_dependency': 1,
+
+  'actions': [
+    {
+      'action_name': 'buildflag_header',
+      'variables': {
+        # Default these values to empty if they're not defined.
+        'variables': {
+          'buildflag_flags%': [],
+        },
+
+        # Writes the flags to a response file with a name based on the name of
+        # this target.
+        'response_file_name': '<|(<(_target_name)_buildflag_header.rsp --flags <@(buildflag_flags))',
+
+        'build_header_script': '<(DEPTH)/build/write_buildflag_header.py',
+      },
+
+      'message': 'Generating build header.',
+
+      'inputs': [
+        '<(build_header_script)',
+        '<(response_file_name)',
+      ],
+
+      'outputs': [
+        '<(SHARED_INTERMEDIATE_DIR)/<(buildflag_header_path)',
+      ],
+
+      'action': [
+        'python', '<(build_header_script)',
+        '--output', '<(buildflag_header_path)',
+        '--rulename', '<(_target_name)',
+        '--gen-dir', '<(SHARED_INTERMEDIATE_DIR)',
+        '--definitions', '<(response_file_name)',
+      ],
+    }
+  ],
+}
diff --git a/build/check_sdk_extras_version.py b/build/check_sdk_extras_version.py
new file mode 100755
index 0000000..3f2e62b
--- /dev/null
+++ b/build/check_sdk_extras_version.py
@@ -0,0 +1,10 @@
+#!/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.
+
+'''Checks the status of an Android SDK package.
+
+TODO(dgn) replaced by a direct update mechanism: http://crbug.com/541727
+This file is now a placeholder until removal after 2 sided patches.
+'''
diff --git a/build/chrome_settings.gypi b/build/chrome_settings.gypi
index e9c7535..646b209 100644
--- a/build/chrome_settings.gypi
+++ b/build/chrome_settings.gypi
@@ -8,6 +8,8 @@
   'variables': {
     # TODO: remove this helper when we have loops in GYP
     'apply_locales_cmd': ['python', '<(DEPTH)/build/apply_locales.py'],
+    'grit_defines': ['-D', 'version=<(version_full)'],
+    'includes': ['util/version.gypi'],
 
     'conditions': [
       ['OS=="mac"', {
diff --git a/build/clobber.py b/build/clobber.py
new file mode 100755
index 0000000..785011a
--- /dev/null
+++ b/build/clobber.py
@@ -0,0 +1,110 @@
+#!/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.
+
+"""This script provides methods for clobbering build directories."""
+
+import argparse
+import os
+import shutil
+import sys
+
+
+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(out_dir):
+  """Clobber contents of build directory.
+
+  Don't delete the 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)
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('out_dir', help='The output directory to clobber')
+  args = parser.parse_args()
+  clobber(args.out_dir)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/common.gypi b/build/common.gypi
index dfa4163..3d12987 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -68,7 +68,7 @@
           # 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%': 1,
 
           # Use OpenSSL for representing certificates. When targeting Android,
           # the platform certificate library is used for certificate
@@ -82,6 +82,18 @@
           # Enable HiDPI support.
           'enable_hidpi%': 0,
 
+          # Enable top chrome material design.
+          'enable_topchrome_md%' : 0,
+
+          # Enable Wayland display server support.
+          'enable_wayland_server%' : 0,
+
+          # By default we build against a stable sysroot image to avoid
+          # depending on the packages installed on the local machine. Set this
+          # to 0 to build against locally installed headers and libraries (e.g.
+          # if packaging for a linux distro)
+          'use_sysroot%': 1,
+
           # Override buildtype to select the desired build flavor.
           # Dev - everyday build for development/testing
           # Official - release build (generally implies additional processing)
@@ -96,15 +108,20 @@
           'branding%': 'Chromium',
 
           'conditions': [
-            # ChromeOS and Windows use Aura and Ash.
-            ['chromeos==1 or OS=="win" or OS=="linux"', {
+            # Windows and Linux (including Chrome OS) use Aura and Ash.
+            ['OS=="win" or OS=="linux"', {
               'use_ash%': 1,
               'use_aura%': 1,
             }],
 
-            ['chromecast==1 and OS!="android"', {
-              'embedded%': 1,
-              'use_ozone%': 1,
+            ['chromecast==1', {
+              'use_libpci': 0,
+              'conditions': [
+                ['OS!="android"', {
+                  'embedded%': 1,
+                  'use_ozone%': 1,
+                }],
+              ],
             }],
 
             # Ozone uses Aura.
@@ -147,6 +164,8 @@
         'use_openssl_certs%': '<(use_openssl_certs)',
         'enable_viewport%': '<(enable_viewport)',
         'enable_hidpi%': '<(enable_hidpi)',
+        'enable_topchrome_md%': '<(enable_topchrome_md)',
+        'enable_wayland_server%': '<(enable_wayland_server)',
         'buildtype%': '<(buildtype)',
         'branding%': '<(branding)',
         'branding_path_component%': '<(branding)',
@@ -171,9 +190,6 @@
         '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.
@@ -217,14 +233,19 @@
             '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 on Mac OS, Windows and Linux (including Chrome OS).
+          ['OS=="mac" 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 Top Chrome Material Design on Chrome OS, Windows, and Linux.
+          ['chromeos==1 or OS=="win" or OS=="linux"', {
+            'enable_topchrome_md%': 1,
+          }],
+
+          # On iOS, use NSS rather than OpenSSL. See http://crbug.com/338886.
+          ['OS=="ios"', {
+            'use_openssl%': 0,
           }],
 
           # Enable App Launcher everywhere but mobile.
@@ -234,7 +255,7 @@
             'enable_app_list%': 0,
           }],
 
-          ['use_aura==1 or (OS!="win" and OS!="mac" and OS!="ios" and OS!="android")', {
+          ['use_aura==1 and OS!="android"', {
             'use_default_render_theme%': 1,
           }, {
             'use_default_render_theme%': 0,
@@ -273,6 +294,28 @@
           ['target_arch=="mipsel"', {
             'mips_arch_variant%': 'r1',
           }],
+
+          # The system root for linux builds.
+          ['OS=="linux" and chromeos==0 and use_sysroot==1', {
+            # sysroot needs to be an absolute path otherwise it generates
+            # incorrect results when passed to pkg-config
+            'conditions': [
+              ['target_arch=="arm"', {
+                'sysroot%': '<!(cd <(DEPTH) && pwd -P)/build/linux/debian_wheezy_arm-sysroot',
+              }],
+              ['target_arch=="x64"', {
+                'sysroot%': '<!(cd <(DEPTH) && pwd -P)/build/linux/debian_wheezy_amd64-sysroot',
+              }],
+              ['target_arch=="ia32"', {
+                'sysroot%': '<!(cd <(DEPTH) && pwd -P)/build/linux/debian_wheezy_i386-sysroot',
+              }],
+              ['target_arch=="mipsel"', {
+                'sysroot%': '<!(cd <(DEPTH) && pwd -P)/build/linux/debian_wheezy_mips-sysroot',
+              }],
+            ],
+          }, {
+            'sysroot%': ''
+          }], # OS=="linux" and use_sysroot==1
         ],
       },
 
@@ -298,6 +341,8 @@
       'use_openssl_certs%': '<(use_openssl_certs)',
       'enable_viewport%': '<(enable_viewport)',
       'enable_hidpi%': '<(enable_hidpi)',
+      'enable_topchrome_md%': '<(enable_topchrome_md)',
+      'enable_wayland_server%': '<(enable_wayland_server)',
       'android_channel%': '<(android_channel)',
       'use_goma%': '<(use_goma)',
       'gomadir%': '<(gomadir)',
@@ -333,6 +378,11 @@
       # Note: this setting is ignored if buildtype=="Official".
       'tracing_like_official_build%': 0,
 
+      # Set to 1 to make a build that disables activation of field trial tests
+      # specified in testing/variations/fieldtrial_testing_config_*.json.
+      # Note: this setting is ignored if branding=="Chrome".
+      'fieldtrial_testing_like_official_build%': 0,
+
       # Disable image loader component extension by default.
       'image_loader_extension%': 0,
 
@@ -357,13 +407,14 @@
       # Enable with GYP_DEFINES=win_analyze=1
       'win_analyze%': 0,
 
+      # /debug:fastlink is off by default on Windows because it generates PDBs
+      # that are machine-local. But, great for local builds.
+      # Enable with GYP_DEFINES=win_fastlink=1
+      'win_fastlink%': 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,
 
@@ -371,16 +422,19 @@
       'configuration_policy%': 1,
 
       # Variable safe_browsing is used to control the build time configuration
-      # for safe browsing feature. Safe browsing can be compiled in 4 different
-      # levels: 0 disables it, 1 enables it fully, and 2 enables only UI and
-      # reporting features for use with Data Saver on Mobile, and 3 enables
-      # extended mobile protection via an external API.  When 3 is fully
-      # deployed, it will replace 2.
+      # for safe browsing feature. Safe browsing can be compiled in 3 different
+      # levels: 0 disables it, 1 enables it fully, and 2 enables mobile
+      # protection via an external API.
       'safe_browsing%': 1,
 
       # Web speech is enabled by default. Set to 0 to disable.
       'enable_web_speech%': 1,
 
+      # 'Ok Google' hotwording is disabled by default. Set to 1 to enable. (This
+      # will download a closed-source NaCl module at startup.) Chrome-branded
+      # ChromeOS builds have this enabled by default.
+      'enable_hotwording%': 0,
+
       # Notifications are compiled in by default. Set to 0 to disable.
       'notifications%' : 1,
 
@@ -446,6 +500,7 @@
       # See http://clang.llvm.org/docs/UsersManual.html
       'ubsan%': 0,
       'ubsan_blacklist%': '<(PRODUCT_DIR)/../../tools/ubsan/blacklist.txt',
+      'ubsan_vptr_blacklist%': '<(PRODUCT_DIR)/../../tools/ubsan/vptr_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
@@ -466,16 +521,6 @@
       # 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,
@@ -493,15 +538,9 @@
       # 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,
 
@@ -510,22 +549,24 @@
       '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.
+      #   1: (DEPRECATED! See http://crbug.com/528305 for info) 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.
+      # Only evaluated if cld_version == 2.
       # See third_party/cld_2/cld_2.gyp for more information.
-      #   0: Small tables, lower accuracy
-      #   2: Large tables, high accuracy
+      #   0: Small tables, high accuracy
+      #   2: Large tables, higher accuracy
       'cld2_table_size%': 2,
 
       # Enable spell checker.
       'enable_spellcheck%': 1,
 
+      # Use the operating system spellchecker, e.g. NSSpellChecker on Mac or
+      # SpellCheckerSession on Android.
+      'use_browser_spellchecker%': 0,
+
       # Webrtc compilation is enabled by default. Set to 0 to disable.
       'enable_webrtc%': 1,
 
@@ -562,10 +603,6 @@
       # 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
@@ -602,22 +639,13 @@
       # 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.
@@ -630,15 +658,19 @@
       # build only explicitly selected platforms.
       'ozone_auto_platforms%': 1,
 
+      # Disable the display for a chromecast build. Set to 1 perform an audio-
+      # only build.
+      'disable_display%': 0,
+
       # 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 Android, when using GCC LTO, 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 (including Android with Clang), 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.
@@ -646,27 +678,28 @@
       # 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.
+      # TODO(pcc): Teach build system to use -lto_library flag to specify path
+      # to linker plugin on Mac.
       #
-      # On Android, the variables must *not* be enabled at the same time.
+      # On Android/GCC, 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',
+      'gold_icf_level%': 'all',
 
       # Libxkbcommon usage.
       'use_xkbcommon%': 0,
 
-      # Control Flow Integrity for virtual calls.
+      # Whether we use GTKv3 on linux.
+      'use_gtk3%': 0,
+
+      # Control Flow Integrity for virtual calls and casts.
       # 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_diag%': 0,
 
       'cfi_blacklist%': '<(PRODUCT_DIR)/../../tools/cfi/blacklist.txt',
 
@@ -722,6 +755,13 @@
           'use_glib%': 1,
         }],
 
+        # Flags to use Wayland server support.
+        ['chromeos==1', {
+          'enable_wayland_server%': 1,
+        }, {
+          'enable_wayland_server%': 0,
+        }],
+
         # Flags to use pango and cairo.
         ['OS=="win" or OS=="mac" or OS=="ios" or OS=="android" or embedded==1', {
           'use_pango%': 0,
@@ -769,25 +809,26 @@
 
         ['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,
+          'cld2_table_size%': 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 and OSX have built-in spellcheckers that can be utilized.
+        ['OS=="android" or OS=="mac"', {
+          'use_browser_spellchecker%': 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.
@@ -797,19 +838,18 @@
           '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,
-            }],
-          ]
+        ['buildtype=="Official"', {
+          'enable_prod_wallet_service%': 1,
+        }],
+
+        # Enable hotwording on Chrome-branded ChromeOS builds.
+        ['branding=="Chrome" and chromeos==1', {
+          'enable_hotwording%': 1,
         }],
 
         ['OS=="android"', {
@@ -817,10 +857,9 @@
         }],
 
         ['OS=="ios"', {
+          'configuration_policy%': 0,
           '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,
@@ -830,10 +869,10 @@
           'enable_webrtc%': 0,
           'notifications%': 0,
           'remoting%': 0,
-          'safe_browsing%': 0,
+          'safe_browsing%': 2,
           'enable_supervised_users%': 0,
           'enable_task_manager%': 0,
-          'use_system_libcxx%': 1,
+          'enable_media_router%': 0,
         }],
 
         # Use GPU accelerated cross process image transport by default
@@ -849,6 +888,13 @@
           'chromium_win_pch%': 1
         }],
 
+        # Whether PDF plugin is enabled.
+        ['OS=="android" or OS=="ios" or (embedded==1 and chromecast==0)', {
+          'enable_pdf%': 0,
+        }, {
+          'enable_pdf%': 1,
+        }],
+
         ['chromeos==1 or OS=="android" or OS=="ios" or desktop_linux==1', {
           'enable_plugin_installation%': 0,
         }, {
@@ -856,7 +902,7 @@
         }],
 
         # Whether PPAPI is enabled.
-        ['OS=="android" or OS=="ios" or embedded==1', {
+        ['OS=="android" or OS=="ios" or (embedded==1 and chromecast==0)', {
           'enable_plugins%': 0,
         }, {
           'enable_plugins%': 1,
@@ -867,7 +913,7 @@
         # 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")', {
+        ['(OS=="linux" or OS=="android") and (target_arch=="x64" or target_arch=="arm" or (target_arch=="ia32" and host_arch=="x64"))', {
           'linux_use_bundled_gold%': 1,
         }, {
           'linux_use_bundled_gold%': 0,
@@ -905,10 +951,8 @@
 
         ['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.
@@ -932,30 +976,6 @@
           '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
@@ -983,15 +1003,6 @@
             '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,
@@ -999,10 +1010,6 @@
           '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"', {
@@ -1010,6 +1017,20 @@
         }, {
           'sas_dll_path%': '<(DEPTH)/third_party/platformsdk_win7/files/redist/x86',
         }],
+
+        ['sysroot!=""', {
+          'pkg-config': '<(chroot_cmd) <(DEPTH)/build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)" "<(system_libdir)"',
+        }, {
+          'pkg-config': 'pkg-config'
+        }],
+
+        # Enable WebVR support by default on Android
+        # Still requires command line flag to access API
+        ['OS=="android"', {
+          'enable_webvr%': 1,
+        }, {
+          'enable_webvr%': 0,
+        }],
       ],
 
       # Setting this to '0' will cause V8's startup snapshot to be
@@ -1067,6 +1088,10 @@
       # Native Client is enabled by default.
       'disable_nacl%': '0',
 
+      # Native Client toolchains, enabled by default.
+      'disable_pnacl%': 0,
+      'disable_newlib%': 0,
+
       # Sets the default version name and code for Android app, by default we
       # do a developer build.
       'android_app_version_name%': 'Developer Build',
@@ -1101,6 +1126,7 @@
     'use_ozone%': '<(use_ozone)',
     'use_ozone_evdev%': '<(use_ozone_evdev)',
     'use_xkbcommon%': '<(use_xkbcommon)',
+    'use_gtk3%': '<(use_gtk3)',
     'use_clipboard_aurax11%': '<(use_clipboard_aurax11)',
     'desktop_linux%': '<(desktop_linux)',
     'use_x11%': '<(use_x11)',
@@ -1110,32 +1136,36 @@
     'chromecast%': '<(chromecast)',
     'enable_viewport%': '<(enable_viewport)',
     'enable_hidpi%': '<(enable_hidpi)',
+    'enable_topchrome_md%': '<(enable_topchrome_md)',
+    'enable_wayland_server%': '<(enable_wayland_server)',
     '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)',
+    'fieldtrial_testing_like_official_build%': '<(fieldtrial_testing_like_official_build)',
     'arm_version%': '<(arm_version)',
     'arm_neon%': '<(arm_neon)',
     'arm_neon_optional%': '<(arm_neon_optional)',
     'sysroot%': '<(sysroot)',
+    'pkg-config%': '<(pkg-config)',
     'chroot_cmd%': '<(chroot_cmd)',
     'system_libdir%': '<(system_libdir)',
     'component%': '<(component)',
     'win_analyze%': '<(win_analyze)',
+    'win_fastlink%': '<(win_fastlink)',
     '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)',
+    'enable_hotwording%': '<(enable_hotwording)',
     'notifications%': '<(notifications)',
     'clang_use_chrome_plugins%': '<(clang_use_chrome_plugins)',
     'mac_want_real_dsym%': '<(mac_want_real_dsym)',
@@ -1156,15 +1186,15 @@
     'tsan_blacklist%': '<(tsan_blacklist)',
     'ubsan%': '<(ubsan)',
     'ubsan_blacklist%': '<(ubsan_blacklist)',
+    'ubsan_vptr_blacklist%': '<(ubsan_vptr_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_pdf%': '<(enable_pdf)',
     'enable_plugin_installation%': '<(enable_plugin_installation)',
     'enable_plugins%': '<(enable_plugins)',
     'enable_session_service%': '<(enable_session_service)',
@@ -1178,17 +1208,15 @@
     '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)',
+    'use_browser_spellchecker%': '<(use_browser_spellchecker)',
     '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)',
@@ -1205,14 +1233,9 @@
     '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)',
@@ -1222,12 +1245,15 @@
     '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_diag%': '<(cfi_diag)',
     '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)',
+    'enable_webvr%': '<(enable_webvr)',
+
+    # Turns on compiler optimizations in V8 in Debug build.
+    'v8_optimized_debug%': 1,
 
     # Use system protobuf instead of bundled one.
     'use_system_protobuf%': 0,
@@ -1327,7 +1353,7 @@
     # 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.
+    # is automatically set to '1' in Official builds.
     'clang_xcode%': 0,
 
     # These two variables can be set in GYP_DEFINES while running
@@ -1395,9 +1421,6 @@
     # 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,
 
@@ -1444,14 +1467,18 @@
     # untrusted toolchain.
     'disable_nacl_untrusted%': 0,
 
+    # PNaCl toolchain does not support sanitizers. Disable by default.
+    'enable_nacl_nonsfi_test%': 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,
+    # Native Client toolchains, enabled by default.
+    'disable_pnacl%': '<(disable_pnacl)',
+    'disable_newlib%': '<(disable_newlib)',
 
     # Whether to build full debug version for Debug configuration on Android.
     # Compared to full debug version, the default Debug configuration on Android
@@ -1465,11 +1492,12 @@
     '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',
+    'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.1',
     '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_support%': 0,
     'enable_rlz%': 0,
 
     # Turns on the i18n support in V8.
@@ -1478,6 +1506,19 @@
     # Compile d8 for the host toolset.
     'v8_toolset_for_d8': 'host',
 
+    # V8 extras
+    # Adding V8 extras files requires API owners review
+    # Be sure to synchronize with build/module_args/v8.gni
+
+    'v8_extra_library_files': [
+      '../third_party/WebKit/Source/core/streams/ReadableStreamTempStub.js',
+    ],
+    'v8_experimental_extra_library_files': [
+      '../third_party/WebKit/Source/core/streams/ByteLengthQueuingStrategy.js',
+      '../third_party/WebKit/Source/core/streams/CountQueuingStrategy.js',
+      '../third_party/WebKit/Source/core/streams/ReadableStream.js',
+    ],
+
     # Use brlapi from brltty for braille display support.
     'use_brlapi%': 0,
 
@@ -1502,12 +1543,10 @@
     # 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,
+    'ozone_platform_headless%': 0,
 
     # Experiment: http://crbug.com/426914
     'envoy%': 0,
@@ -1581,11 +1620,6 @@
         '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)',
       }, {
@@ -1602,10 +1636,6 @@
             '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"', {
@@ -1683,9 +1713,24 @@
             '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',
+            'android_sdk_version%': '23',
+            'android_sdk_build_tools_version%': '23.0.1',
             'host_os%': "<!(uname -s | sed -e 's/Linux/linux/;s/Darwin/mac/')",
+
+            'conditions': [
+              # Figure this out early since it needs symbols from libgcc.a, so it
+              # has to be before that in the set of libraries.
+              # ASan needs to dynamically link to libc++ even in static builds so
+              # that it can interpose operator new.
+              ['component=="shared_library" or asan==1', {
+                  'android_libcpp_library': 'c++_shared',
+                  'android_must_copy_system_libraries': 1,
+              }, {
+                  'android_libcpp_library': 'c++_static',
+                  'android_must_copy_system_libraries': 0,
+              }],
+            ],
+
           },
           # Copy conditionally-set variables out one scope.
           'android_ndk_root%': '<(android_ndk_root)',
@@ -1693,20 +1738,22 @@
           'android_sdk_root%': '<(android_sdk_root)',
           'android_sdk_version%': '<(android_sdk_version)',
           'android_libcpp_root': '<(android_ndk_root)/sources/cxx-stl/llvm-libc++',
+          'android_libcpp_library': '<(android_libcpp_library)',
+          'android_must_copy_system_libraries': '<(android_must_copy_system_libraries)',
           '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 build tools (e.g. dx, 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
+          # Android API level 16 is JB (Android 4.1) 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_sysroot%': '<(android_ndk_root)/platforms/android-16/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',
             }],
@@ -1726,7 +1773,7 @@
                 }],
               ],
               'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-arm/gdbserver/gdbserver',
-              'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-14/arch-arm',
+              'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-16/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',
             }],
@@ -1740,7 +1787,7 @@
             ['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_sysroot%': '<(android_ndk_root)/platforms/android-16/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',
             }],
@@ -1765,12 +1812,15 @@
         '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_aapt_path%': '<(android_sdk_tools)/aapt',
         'android_sdk%': '<(android_sdk)',
         'android_sdk_jar%': '<(android_sdk)/android.jar',
 
         'android_libcpp_root': '<(android_libcpp_root)',
+        'android_libcpp_library': '<(android_libcpp_library)',
         'android_libcpp_include': '<(android_libcpp_root)/libcxx/include',
-        'android_libcpp_libs_dir': '<(android_libcpp_root)/libs/<(android_app_abi)',
+        'android_libcpp_libs_dir%': '<(android_libcpp_root)/libs/<(android_app_abi)',
+        'android_must_copy_system_libraries': '<(android_must_copy_system_libraries)',
         'host_os%': '<(host_os)',
 
         # Location of the "objcopy" binary, used by both gyp and scripts.
@@ -1788,15 +1838,15 @@
         # developer builds, to avoid spurious re-linking of native files.
         'optimize_jni_generation%': '<(optimize_jni_generation)',
 
-        # Always uses openssl.
-        'use_openssl%': 1,
+        # Use OpenSSL's struct X509 to represent certificates.
         '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.
@@ -1821,20 +1871,17 @@
         'enable_mpeg2ts_stream_parser%': 1,
         'ffmpeg_branding%': 'ChromeOS',
         'ozone_platform_ozonex%': 1,
+        'use_custom_freetype%': 0,
         '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"', {
+      ['OS=="linux"', {
         'clang%': 1,
       }],  # OS=="mac"
       ['OS=="mac"', {
@@ -1874,13 +1921,17 @@
           'conditions': [
             ['OS=="ios"', {
               'mac_sdk_min%': '10.8',
+              # The iOS build can use Xcode's clang, and that will complain
+              # about -stdlib=libc++ if the deployment target is not at least
+              # 10.7.
+              'mac_deployment_target%': '10.7',
             }, {  # else OS!="ios"
-              'mac_sdk_min%': '10.6',
+              'mac_sdk_min%': '10.10',
+              'mac_deployment_target%': '10.6',
             }],
           ],
           'mac_sdk_path%': '',
 
-          'mac_deployment_target%': '10.6',
         },
 
         'mac_sdk_min': '<(mac_sdk_min)',
@@ -1944,6 +1995,13 @@
           ['asan==1 or syzyasan==1', {
             'win_use_allocator_shim%': 0,
           }],
+          # The AddressSanitizer build should be a console program as it prints
+          # out stuff on stderr.
+          ['asan==1', {
+            'win_console_app%': 1,
+          }, {
+            'win_console_app%': 0,
+          }],
           ['syzyasan==1', {
             'kasko%': 1,
           }],
@@ -1978,7 +2036,7 @@
         'use_cups%': 0,
       }],
 
-      ['enable_plugins==1 and (OS=="linux" or OS=="mac" or OS=="win")', {
+      ['enable_plugins==1 and (OS=="linux" or OS=="mac" or OS=="win") and chromecast==0', {
         'enable_pepper_cdms%': 1,
       }, {
         'enable_pepper_cdms%': 0,
@@ -1990,9 +2048,8 @@
         '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"', {
+      # Native Client glibc toolchain is enabled except on mips
+      ['target_arch=="mipsel" or target_arch=="mips64el"', {
         'disable_glibc%': 1,
       }, {
         'disable_glibc%': 0,
@@ -2051,19 +2108,9 @@
       ['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',
@@ -2123,9 +2170,6 @@
       ['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'],
       }],
@@ -2144,12 +2188,12 @@
       ['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_topchrome_md==1', {
+        'grit_defines': ['-D', 'enable_topchrome_md'],
+      }],
       ['enable_resource_whitelist_generation==1 and OS!="win"', {
         'grit_rc_header_format': ['-h', '#define {textual_id} _Pragma("whitelisted_resource_{numeric_id}") {numeric_id}'],
       }],
@@ -2178,20 +2222,25 @@
               # On Windows, the plugin is built directly into clang, so there's
               # no need to load it dynamically.
               'clang_dynlib_flags%': '',
-            }]
+            }],
           ],
+          'clang_plugin_args%': '-Xclang -plugin-arg-find-bad-constructs -Xclang check-templates ',
         },
         # 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 ',
+          '-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',
+      }],
+
+      ['OS=="linux" and asan==0 and msan==0 and lsan==0 and tsan==0', {
+        # PNaCl toolchain Non-SFI build only supports linux OS build.
+        # Also, it does not support sanitizers.
+        'enable_nacl_nonsfi_test%': 1,
       }],
       ['asan==1 and OS=="linux" and chromeos==0', {
         'use_custom_libcxx%': 1,
@@ -2219,29 +2268,6 @@
         '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" and target_arch=="x64"', {
-        # TODO(thakis): Enable on x64 once all warnings are fixed.
-        # http://crbug.com/486571
-        '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.
       #
@@ -2295,9 +2321,15 @@
         '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,
+      # RLZ library is used on Win, Mac, iOS and ChromeOS.
+      ['OS=="win" or OS=="mac" or OS=="ios" or chromeos==1', {
+        'enable_rlz_support%': 1,
+        'conditions': [
+          # RLZ is enabled for "Chrome" builds.
+          ['branding=="Chrome"', {
+            'enable_rlz%': 1,
+          }],
+        ],
       }],
 
       # Set default compiler flags depending on ARM version.
@@ -2317,9 +2349,12 @@
           }, {
             'arm_fpu%': 'vfpv3-d16',
           }],
+          ['OS=="android"', {
+            'arm_float_abi%': 'softfp',
+          }, {
+            'arm_float_abi%': 'hard',
+          }],
         ],
-        # Change the default to hard once the armhf transition is complete.
-        'arm_float_abi%': 'softfp',
         'arm_thumb%': 1,
       }],
 
@@ -2329,23 +2364,46 @@
       }],
       ['target_arch=="mipsel" and mips_arch_variant=="r2"', {
         'mips_fpu_mode%': 'fp32',
+      }, {
+        'mips_fpu_mode%': '',
       }],
 
       # Enable brlapi by default for chromeos.
-      [ 'chromeos==1', {
+      ['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,
+        # Use headless as the default platform.
+        'ozone_platform%': 'headless',
+        'ozone_platform_headless%': 1,
+        'conditions': [
+          ['chromecast==1', {
+            'conditions': [
+              ['disable_display==0', {
+                # Enable the Cast ozone platform on all A/V Cast builds.
+                'ozone_platform_cast%': 1,
+                'conditions': [
+                  ['OS=="linux" and target_arch!="arm"', {
+                    'ozone_platform_egltest%': 1,
+                    'ozone_platform_ozonex%': 1,
+                  }],
+                ],
+              }],
+            ],
+          }, {  # chromecast!=1
+            'conditions': [
+              ['OS=="chromeos"', {
+                'ozone_platform_gbm%': 1,
+                'ozone_platform_egltest%': 1,
+              }, {
+                # Build all platforms whose deps are in install-build-deps.sh.
+                # Only these platforms will be compile tested by buildbots.
+                'ozone_platform_egltest%': 1,
+              }],
+            ],
+          }],
+        ],
       }],
 
       ['desktop_linux==1 and use_aura==1 and use_x11==1', {
@@ -2388,9 +2446,15 @@
          'use_seccomp_bpf%': 0,
       }],
 
-      ['cfi_vptr==1 or cfi_derived_cast==1 or cfi_unrelated_cast==1', {
+      ['cfi_vptr==1', {
         'use_lto%': 1,
       }],
+
+      ['branding=="Chrome" and buildtype=="Official"', {
+        'enable_hangout_services_extension%': 1,
+      }, {
+        'enable_hangout_services_extension%': 0,
+      }],
     ],
 
     # The path to the ANGLE library.
@@ -2427,6 +2491,9 @@
 
      # Whether to allow building of chromoting related isolates.
     'archive_chromoting_tests%': 0,
+
+    # Whether to allow building of Media Router related isolates.
+    'archive_media_router_tests%': 0,
   },
   'target_defaults': {
     'variables': {
@@ -2568,19 +2635,31 @@
         # http://crbug.com/255186
         '-Wno-deprecated-register',
 
-        # TODO(hans): Get this cleaned up.
+        # TODO(hans): Get this cleaned up, http://crbug.com/428099
         '-Wno-inconsistent-missing-override',
+
+        # TODO(thakis): Enable this, crbug.com/507717
+        '-Wno-shift-negative-value',
+
+        # TODO(thakis): Consider enabling this?
+        '-Wno-bitfield-width',
       ],
     },
     'includes': [ 'set_clang_warning_flags.gypi', ],
     'defines': [
       # Don't use deprecated V8 APIs anywhere.
       'V8_DEPRECATION_WARNINGS',
+      'CLD_VERSION=<(cld_version)',
     ],
     'include_dirs': [
       '<(SHARED_INTERMEDIATE_DIR)',
     ],
     'conditions': [
+      ['OS=="mac"', {
+        # When compiling Objective C, warns if a method is used whose
+        # availability is newer than the deployment target.
+        'xcode_settings': { 'WARNING_CFLAGS': ['-Wpartial-availability']},
+      }],
       ['(OS=="mac" or OS=="ios") and asan==1', {
         'dependencies': [
           '<(DEPTH)/build/mac/asan.gyp:asan_dynamic_runtime',
@@ -2591,18 +2670,6 @@
           '<(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"
@@ -2633,9 +2700,6 @@
       ['component=="shared_library"', {
         'defines': ['COMPONENT_BUILD'],
       }],
-      ['toolkit_views==1', {
-        'defines': ['TOOLKIT_VIEWS=1'],
-      }],
       ['ui_compositor_image_transport==1', {
         'defines': ['UI_COMPOSITOR_IMAGE_TRANSPORT'],
       }],
@@ -2672,18 +2736,12 @@
       ['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'],
       }],
@@ -2716,8 +2774,11 @@
       ['enable_hidpi==1', {
         'defines': ['ENABLE_HIDPI=1'],
       }],
-      ['native_memory_pressure_signals==1', {
-        'defines': ['SYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE'],
+      ['enable_topchrome_md==1', {
+        'defines': ['ENABLE_TOPCHROME_MD=1'],
+      }],
+      ['enable_wayland_server==1', {
+        'defines': ['ENABLE_WAYLAND_SERVER=1'],
       }],
       ['use_udev==1', {
         'defines': ['USE_UDEV'],
@@ -2781,6 +2842,9 @@
       ['tracing_like_official_build!=0', {
         'defines': ['TRACING_IS_OFFICIAL_BUILD=1'],
       }],  # tracing_like_official_build!=0
+      ['fieldtrial_testing_like_official_build==0 and branding!="Chrome"', {
+        'defines': ['FIELDTRIAL_TESTING_ENABLED'],
+      }],  # fieldtrial_testing_like_official_build==0 and branding!="Chrome"
       ['OS=="win"', {
         'defines': ['NO_TCMALLOC'],
         'conditions': [
@@ -2859,8 +2923,7 @@
                 # override WarnAsError.
                 # Also, disable various noisy warnings that have low value.
                 'AdditionalOptions': [
-                  '/analyze',
-                  '/WX-',
+                  '/analyze:WX-',
                   '/wd6011',  # Dereferencing NULL pointer
                   '/wd6312',  # Possible infinite loop: use of the constant
                     # EXCEPTION_CONTINUE_EXECUTION in the exception-filter
@@ -2912,6 +2975,9 @@
       ['enable_dart==1', {
         'defines': ['WEBKIT_USING_DART=1'],
       }],
+      ['enable_pdf==1', {
+        'defines': ['ENABLE_PDF=1'],
+      }],
       ['enable_plugin_installation==1', {
         'defines': ['ENABLE_PLUGIN_INSTALLATION=1'],
       }],
@@ -2935,12 +3001,6 @@
       ['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'],
@@ -2957,6 +3017,9 @@
       ['enable_spellcheck==1', {
         'defines': ['ENABLE_SPELLCHECK=1'],
       }],
+      ['use_browser_spellchecker', {
+        'defines': ['USE_BROWSER_SPELLCHECKER=1'],
+      }],
       ['enable_captive_portal_detection==1', {
         'defines': ['ENABLE_CAPTIVE_PORTAL_DETECTION=1'],
       }],
@@ -2975,21 +3038,12 @@
       ['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'],
       }],
@@ -3002,8 +3056,10 @@
       ['v8_use_external_startup_data==1', {
        'defines': ['V8_USE_EXTERNAL_STARTUP_DATA'],
       }],
+      ['enable_webvr==1', {
+        'defines': ['ENABLE_WEBVR'],
+      }],
 
-      # 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.
@@ -3013,22 +3069,11 @@
           'FULL_SAFE_BROWSING',
           'SAFE_BROWSING_CSD',
           'SAFE_BROWSING_DB_LOCAL',
-          'SAFE_BROWSING_SERVICE',
         ],
       }],
-      ['safe_browsing==2', {
+      ['safe_browsing==2 and OS!="ios"', {
         'defines': [
-          # TODO(nparker): Remove existing uses of MOBILE_SAFE_BROWSING
-          'MOBILE_SAFE_BROWSING',
-          'SAFE_BROWSING_SERVICE',
-        ],
-      }],
-      ['safe_browsing==3', {
-        'defines': [
-          # TODO(nparker): Remove existing uses of MOBILE_SAFE_BROWSING
-          'MOBILE_SAFE_BROWSING',
           'SAFE_BROWSING_DB_REMOTE',
-          'SAFE_BROWSING_SERVICE',
         ],
       }],
     ],  # conditions for 'target_defaults'
@@ -3062,6 +3107,13 @@
         'variables': { 'clang_warning_flags': ['-Wexit-time-destructors']},
       }],
       ['chromium_code==0', {
+        'variables': {
+          'clang_warning_flags': [
+            # Lots of third-party libraries have unused variables. Instead of
+            # suppressing them individually, we just blanket suppress them here.
+            '-Wno-unused-variable',
+          ],
+        },
         'conditions': [
           [ 'os_posix==1 and OS!="mac" and OS!="ios"', {
             # We don't want to get warnings from third-party code,
@@ -3107,11 +3159,6 @@
               '_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': {
@@ -3206,9 +3253,14 @@
           'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)',
           'CharacterSet': '1',
         },
-        # Add the default import libs.
         'msvs_settings':{
+          'VCCLCompilerTool': {
+            'AdditionalOptions': [
+              '/bigobj',
+            ],
+          },
           'VCLinkerTool': {
+            # Add the default import libs.
             'AdditionalDependencies': [
               'kernel32.lib',
               'gdi32.lib',
@@ -3235,6 +3287,32 @@
             ],
           },
         },
+        'conditions': [
+          ['OS=="win" and win_fastlink==1', {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                # /PROFILE is incompatible with /debug:fastlink
+                'Profile': 'false',
+                'AdditionalOptions': [
+                  # Tell VS 2015+ to create a PDB that references debug
+                  # information in .obj and .lib files instead of copying
+                  # it all.
+                  '/DEBUG:FASTLINK',
+                ],
+              },
+            },
+          }],
+          ['OS=="win" and MSVS_VERSION == "2015"', {
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  # Work around crbug.com/526851, bug in VS 2015 RTM compiler.
+                  '/Zc:sizedDealloc-',
+                ],
+              },
+            },
+          }],
+        ],
       },
       'x86_Base': {
         'abstract': 1,
@@ -3586,7 +3664,7 @@
       },
     }],
     # -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', {
+    ['(OS=="linux" or OS=="android") and asan==0 and msan==0 and tsan==0 and ubsan==0 and ubsan_vptr==0 and cfi_diag==0', {
       'target_defaults': {
         'ldflags': [
           '-Wl,-z,defs',
@@ -3666,7 +3744,6 @@
             'cflags': [
               '-O>(debug_optimize)',
               '-g',
-              '-gdwarf-4',
             ],
             'conditions' : [
               ['OS=="android" and target_arch!="mipsel" and target_arch!="mips64el"', {
@@ -3851,19 +3928,14 @@
                 'conditions': [
                   # Use gold linker for Android ia32 target.
                   ['OS=="android"', {
+                     # Use gold linker for Android ia32 target.
                     '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',
+                    # Use -mstackrealign due to a bug on ia32 Jelly Bean.
+                    # See crbug.com/521527
+                    'cflags': [
+                      '-mstackrealign',
                     ],
                   }],
                 ],
@@ -3924,13 +3996,6 @@
                       }],
                     ],
                   }],
-                  ['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)',
@@ -4044,11 +4109,6 @@
                           '-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': [
@@ -4134,6 +4194,9 @@
                           ['OS=="android"', {
                             'cflags': [ '-target mipsel-linux-android', '-march=mipsel', '-mcpu=mips32r2'],
                             'ldflags': [ '-target mipsel-linux-android', ],
+                          }, {
+                            'cflags': [ '-target mipsel-linux-gnu', '-march=mipsel', '-mcpu=mips32r2'],
+                            'ldflags': [ '-target mipsel-linux-gnu', ],
                           }],
                          ],
                       }, { # clang==0
@@ -4148,6 +4211,9 @@
                           ['OS=="android"', {
                             'cflags': [ '-target mipsel-linux-android', '-march=mipsel', '-mcpu=mips32'],
                             'ldflags': [ '-target mipsel-linux-android', ],
+                          }, {
+                            'cflags': [ '-target mipsel-linux-gnu', '-march=mipsel', '-mcpu=mips32'],
+                            'ldflags': [ '-target mipsel-linux-gnu', ],
                           }],
                         ],
                       }, { # clang==0
@@ -4163,8 +4229,9 @@
                     'cflags': [
                       # TODO(gordanac) Enable integrated-as.
                       '-no-integrated-as',
-                      '-B<(android_toolchain)',  # Else /usr/bin/as gets picked up.
                     ],
+                  }],
+                  ['clang==1 and OS=="android"', {
                     'ldflags': [
                       # Let clang find the ld in the NDK.
                       '--gcc-toolchain=<(android_toolchain)/..',
@@ -4280,8 +4347,9 @@
             ],
           }],
           # 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', {
+          # ThreadSanitizer, MemorySanitizer and non-official CFI builds.
+          ['asan==1 or lsan==1 or tsan==1 or msan==1 or ubsan==1 or ubsan_vptr==1 or '
+           '(cfi_vptr==1 and buildtype!="Official")', {
             'target_conditions': [
               ['_toolset=="target"', {
                 'cflags': [
@@ -4335,7 +4403,19 @@
             'target_conditions': [
               ['_toolset=="target"', {
                 'cflags': [
-                  '-fsanitize=undefined',
+                  # FIXME: work on enabling more flags and getting rid of false
+                  # positives. http://crbug.com/174801.
+                  '-fsanitize=bounds',
+                  '-fsanitize=float-divide-by-zero',
+                  '-fsanitize=integer-divide-by-zero',
+                  '-fsanitize=null',
+                  '-fsanitize=object-size',
+                  '-fsanitize=return',
+                  '-fsanitize=returns-nonnull-attribute',
+                  '-fsanitize=shift-exponent',
+                  '-fsanitize=signed-integer-overflow',
+                  '-fsanitize=unreachable',
+                  '-fsanitize=vla-bound',
                   '-fsanitize-blacklist=<(ubsan_blacklist)',
                   # Employ the experimental PBQP register allocator to avoid
                   # slow compilation on files with too many basic blocks.
@@ -4365,7 +4445,7 @@
               ['_toolset=="target"', {
                 'cflags': [
                   '-fsanitize=vptr',
-                  '-fsanitize-blacklist=<(ubsan_blacklist)',
+                  '-fsanitize-blacklist=<(ubsan_vptr_blacklist)',
                 ],
                 'cflags_cc!': [
                   '-fno-rtti',
@@ -4406,6 +4486,15 @@
               }],
             ],
           }],
+          ['(asan_coverage>1 or sanitizer_coverage>1) and target_arch=="arm"', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-mllvm -sanitizer-coverage-block-threshold=0',  # http://crbug.com/517105
+                ],
+              }],
+            ],
+          }],
           ['asan_field_padding!=0', {
             'target_conditions': [
               ['_toolset=="target"', {
@@ -4456,9 +4545,13 @@
                   '-fsanitize=memory',
                   '-fsanitize-memory-track-origins=<(msan_track_origins)',
                   '-fsanitize-blacklist=<(msan_blacklist)',
+                  # TODO(eugenis): Remove when msan migrates to new ABI (crbug.com/560589).
+                  '-fPIC',
                 ],
                 'ldflags': [
                   '-fsanitize=memory',
+                  # TODO(eugenis): Remove when msan migrates to new ABI (crbug.com/560589).
+                  '-pie',
                 ],
                 'defines': [
                   'MEMORY_SANITIZER',
@@ -4481,23 +4574,25 @@
               '<(DEPTH)/buildtools/third_party/libc++/libc++.gyp:libcxx_proxy',
             ],
           }],
-          ['order_profiling!=0 and (chromeos==1 or OS=="linux" or OS=="android")', {
+          ['order_profiling!=0 and 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"', {
+                'cflags': ['-finstrument-functions'],
+                'defines': ['CYGPROFILE_INSTRUMENTATION'],
               }],
-              ['_toolset=="target" and OS=="android"', {
+            ],
+          }],
+          # Clang doesn't understand -finstrument-functions-exclude-file-list=.
+          ['order_profiling!=0 and OS=="android" and clang==0', {
+            'target_conditions' : [
+              ['_toolset=="target"', {
                 'cflags': [
+                  # Allow mmx intrinsics to inline, so that the
+                  # compiler can expand the intrinsics.
+                  '-finstrument-functions-exclude-file-list=mmintrin.h',
                   # 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',
+                  '-finstrument-functions-exclude-file-list=arm_neon.h',
                 ],
               }],
             ],
@@ -4552,7 +4647,7 @@
               }],
             ],
             'conditions': [
-              ['release_valgrind_build==0 and order_profiling==0', {
+              ['release_valgrind_build==0 and order_profiling==0 and asan==0 and msan==0 and lsan==0 and tsan==0', {
                 'target_conditions': [
                   ['_toolset=="target"', {
                     'ldflags': [
@@ -4640,22 +4735,13 @@
         # 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.
+        # in third_party/libvpx_new/libvpx.gyp to define it.
         'libvpx_path': 'lib/linux/arm',
       },
       'target_defaults': {
@@ -4746,6 +4832,7 @@
               '-pthread',  # Not supported by Android toolchain.
             ],
             'ldflags': [
+              '-Wl,--build-id=sha1',
               '-Wl,--no-undefined',
               '--sysroot=<(android_ndk_sysroot)',
               '-nostdlib',
@@ -4798,6 +4885,10 @@
                   '-D__compiler_offsetof=__builtin_offsetof',
                   '-Dnan=__builtin_nan',
                 ],
+                'cflags!': [
+                  # Clang does not support the following options.
+                  '-finline-limit=64',
+                ],
                 'conditions': [
                   ['target_arch=="arm"', {
                     'cflags': [
@@ -4809,14 +4900,24 @@
                   }],
                   ['target_arch=="ia32"', {
                     'cflags': [
-                      '-target x86-linux-androideabi',
+                      '-target i686-linux-androideabi',
                     ],
                     'ldflags': [
-                      '-target x86-linux-androideabi',
+                      '-target i686-linux-androideabi',
+                    ],
+                  }],
+                  # Place holder for arm64 support, not tested.
+                  # TODO: Enable clang support for Android Arm64. http://crbug.com/539781
+                  ['target_arch=="arm64"', {
+                    'cflags': [
+                      '-target aarch64-linux-androideabi',
+                    ],
+                    'ldflags': [
+                      '-target aarch64-linux-androideabi',
                     ],
                   }],
                   # Place holder for x64 support, not tested.
-                  # TODO: Enable clang support for Android x64. http://crbug.com/346626
+                  # TODO: Enable clang support for Android x64. http://crbug.com/539781
                   ['target_arch=="x64"', {
                     'cflags': [
                       '-target x86_64-linux-androideabi',
@@ -5156,6 +5257,28 @@
           },  # configuration "Release"
         },  # configurations
         'xcode_settings': {
+          # Tell the compiler to use libc++'s headers and the linker to link
+          # against libc++.  The latter part normally requires OS X 10.7,
+          # but we still support running on 10.6.  How does this work?  Two
+          # parts:
+          # 1. Chromium's clang doesn't error on -mmacosx-version-min=10.6
+          #    combined with -stdlib=libc++ (it normally silently produced a
+          #    binary that doesn't run on 10.6)
+          # 2. Further down, library_dirs is set to
+          #    third_party/libc++-static, which contains a static
+          #    libc++.a library.  The linker then links against that instead
+          #    of against /usr/lib/libc++.dylib when it sees the -lc++ flag
+          #    added by the driver.
+          #
+          # In component builds, just link to the system libc++.  This has
+          # the effect of making everything depend on libc++, which means
+          # component-build binaries won't run on 10.6 (no libc++ there),
+          # but for a developer-only configuration that's ok.  (We don't
+          # want to raise the deployment target yet so that official and
+          # dev builds have the same deployment target.  This affects
+          # things like which functions are considered deprecated.)
+          'CLANG_CXX_LIBRARY': 'libc++',  # -stdlib=libc++
+
           'GCC_DYNAMIC_NO_PIC': 'NO',               # No -mdynamic-no-pic
                                                     # (Equivalent to -fPIC)
           # MACOSX_DEPLOYMENT_TARGET maps to -mmacosx-version-min
@@ -5174,6 +5297,18 @@
           ],
         },
         'target_conditions': [
+          ['>(nacl_untrusted_build)==0 and component=="static_library"', {
+            # See the comment for CLANG_CXX_LIBRARY above for what this does.
+            # The NaCl toolchains have their own toolchain and don't need this.
+            # ASan requires 10.7+ and clang implicitly adds -lc++abi in ASan
+            # mode.  Our libc++.a contains both libc++ and libc++abi in one
+            # library, so it doesn't work in that mode.
+            'conditions': [
+              ['asan==0', {
+                'library_dirs': [ '<(DEPTH)/third_party/libc++-static' ],
+              }],
+            ],
+          }],
           ['_type=="executable"', {
             'postbuilds': [
               {
@@ -5288,7 +5423,8 @@
       ],
       'target_defaults': {
         'xcode_settings' : {
-          'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
+          'ENABLE_BITCODE': 'NO',
+          'CLANG_CXX_LIBRARY': 'libc++',  # -stdlib=libc++
 
           'conditions': [
             # Older Xcodes do not support -Wno-deprecated-register, so pass an
@@ -5301,6 +5437,9 @@
             ['clang_xcode==1', {
               'WARNING_CFLAGS': [
                 '-Wno-unknown-warning-option',
+                # It's not possible to achieve nullability completeness before
+                # all builders are running Xcode 7. crbug.com/499809
+                '-Wno-nullability-completeness',
               ],
             }],
 
@@ -5316,20 +5455,6 @@
             ['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': [
@@ -5343,6 +5468,17 @@
               'ARCHS': [
                 'x86_64',
               ],
+              'WARNING_CFLAGS': [
+                # TODO(thakis): Remove this once the deployment target on OS X
+                # is 10.7 too, http://crbug.com/547071
+                # In general, it is NOT OK to add -Wno-deprecated-declarations
+                # anywhere, you should instead fix your code instead.  But host
+                # compiles on iOS are really mac compiles, so this will be fixed
+                # when the mac deployment target is increased.  (Some of the
+                # fixes depend on OS X 10.7 so they can't be done before mac
+                # upgrades).
+                '-Wno-deprecated-declarations',
+              ],
             },
           }],
           ['_toolset=="target"', {
@@ -5360,6 +5496,12 @@
                 'xcode_settings': {
                   'DEPLOYMENT_POSTPROCESSING': 'YES',
                   'STRIP_INSTALLED_PRODUCT': 'YES',
+                  'conditions': [
+                    ['buildtype!="Official"', {
+                      # Remove dSYM to reduce build time.
+                      'DEBUG_INFORMATION_FORMAT': 'dwarf',
+                    }],
+                  ],
                 },
               },
               'Debug_Base': {
@@ -5440,6 +5582,19 @@
                     },
                   },
                 ],
+                # This config is used to avoid a problem in ffmpeg, see
+                # http://crbug.com/264459.
+                ['optimize=="size_no_ltcg"', {
+                    'msvs_settings': {
+                      'VCCLCompilerTool': {
+                        # 1, optimizeMinSpace, Minimize Size (/O1)
+                        'Optimization': '1',
+                        # 2, favorSize - Favor small code (/Os)
+                        'FavorSizeOrSpeed': '2',
+                      },
+                    },
+                  },
+                ],
                 ['optimize=="speed"', {
                     'msvs_settings': {
                       'VCCLCompilerTool': {
@@ -5530,6 +5685,12 @@
           # trying to prevent it.
           4503,
 
+          # Warning C4589 says: "Constructor of abstract class ignores
+          # initializer for virtual base class." Disable this warning because it
+          # is flaky in VS 2015 RTM. It triggers on compiler generated
+          # copy-constructors in some cases.
+          4589,
+
           # C4611: interaction between 'function' and C++ object destruction is
           #        non-portable
           # This warning is unavoidable when using e.g. setjmp/longjmp.  MSDN
@@ -5550,6 +5711,8 @@
           4510, # Default constructor could not be generated
           4512, # Assignment operator could not be generated
           4610, # Object can never be instantiated
+          4838, # Narrowing conversion. Doesn't seem to be very useful.
+          4995, # 'X': name was marked as #pragma deprecated
           4996, # 'X': was declared deprecated (for GetVersionEx).
 
           # These are variable shadowing warnings that are new in VS2015. We
@@ -5594,7 +5757,6 @@
             ],
             'GenerateDebugInformation': 'true',
             'MapFileName': '$(OutDir)\\$(TargetName).map',
-            'ImportLibrary': '$(OutDir)\\lib\\$(TargetName).lib',
             'FixedBaseAddress': '1',
             # SubSystem values:
             #   0 == not set
@@ -5637,57 +5799,23 @@
           'conditions': [
             # Building with Clang on Windows is a work in progress and very
             # experimental. See crbug.com/82385.
+            # Keep this in sync with the similar blocks in build/config/compiler/BUILD.gn
             ['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',
+                  # TODO(hans): Make this list shorter eventually, http://crbug.com/504657
+                  '-Qunused-arguments',  # http://crbug.com/504658
+                  '-Wno-microsoft-enum-value',  # http://crbug.com/505296
+                  '-Wno-unknown-pragmas',  # http://crbug.com/505314
+                  '-Wno-microsoft-cast',  # http://crbug.com/550065
+                  # Disable unused-value (crbug.com/505318) except
+                  # -Wunused-result.
                   '-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',
+                  '-Wunused-result',
                 ],
               },
             }],
@@ -5698,6 +5826,31 @@
                 ],
               },
             }],
+            ['clang==1 and MSVS_VERSION == "2013"', {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  '-fmsc-version=1800',
+                ],
+              },
+            }],
+            ['clang==1 and MSVS_VERSION == "2015"', {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  '-fmsc-version=1900',
+                ],
+              },
+            }],
+            ['clang==1 and "<!(python <(DEPTH)/build/win/use_ansi_codes.py)"=="True"', {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  # cmd.exe doesn't understand ANSI escape codes by default,
+                  # so only enable them if something emulating them is around.
+                  '-fansi-escape-codes',
+                  # Also see http://crbug.com/110262
+                  '-fcolor-diagnostics',
+                ],
+              },
+            }],
           ],
         },
       },
@@ -5753,13 +5906,13 @@
                       # 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',
+                      '<(DEPTH)/<(make_clang_dir)/lib/clang/<!(python <(DEPTH)/tools/clang/scripts/update.py --print-clang-version)/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',
+                      '<(DEPTH)/<(make_clang_dir)/lib/clang/<!(python <(DEPTH)/tools/clang/scripts/update.py --print-clang-version)/lib/windows',
                     ],
                   },
                   'target_conditions': [
@@ -5867,9 +6020,12 @@
     }],
     ['use_lld==1 and OS=="win"', {
       'make_global_settings': [
-        # Limited to Windows because lld-link is the driver that is compatible
-        # to link.exe.
+        # Limited to Windows because lld-link is the driver that is
+        # compatible with link.exe.
         ['LD', '<(make_clang_dir)/bin/lld-link'],
+        # lld-link includes a replacement for lib.exe that can produce thin
+        # archives and understands bitcode (for use_lto==1).
+        ['AR', '<(make_clang_dir)/bin/lld-link /lib /llvmlibthin'],
       ],
     }],
     ['OS=="android" and clang==0', {
@@ -5882,17 +6038,19 @@
         ['CXX.host', '<(host_cxx)'],
       ],
     }],
-    ['OS=="linux" and target_arch=="mipsel"', {
+    ['OS=="linux" and target_arch=="mipsel" and host_arch!="mipsel" and chromeos==0 and clang==0', {
+      # Set default mips cross tools on linux.  These can be overridden
+      # using CC,CXX,CC.host and CXX.host environment variables.
       'make_global_settings': [
-        ['CC', '<(sysroot)/../bin/mipsel-linux-gnu-gcc'],
-        ['CXX', '<(sysroot)/../bin/mipsel-linux-gnu-g++'],
+        ['CC', '<!(which mipsel-linux-gnu-gcc)'],
+        ['CXX', '<!(which 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.
+      # Set default ARM cross tools on linux.  These can be overridden
+      # using CC,CXX,CC.host and CXX.host environment variables.
       'make_global_settings': [
         ['CC', '<!(which arm-linux-gnueabihf-gcc)'],
         ['CXX', '<!(which arm-linux-gnueabihf-g++)'],
@@ -5900,7 +6058,6 @@
         ['CXX.host', '<(host_cxx)'],
       ],
     }],
-
     # TODO(yyanagisawa): supports GENERATOR==make
     #  make generator doesn't support CC_wrapper without CC
     #  in make_global_settings yet.
@@ -5954,10 +6111,19 @@
             ],
           }],
         ],
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'AdditionalOptions': [
+              # TODO(pcc): Add LTO support to clang-cl driver and use it here.
+              '-Xclang',
+              '-emit-llvm-bc',
+            ],
+          },
+        },
       },
     }],
-    # Apply a lower LTO optimization level in non-official builds.
-    ['use_lto==1 and clang==1 and buildtype!="Official"', {
+    # Apply a lower LTO optimization level as the default is too slow.
+    ['use_lto==1 and clang==1', {
       'target_defaults': {
         'target_conditions': [
           ['_toolset=="target"', {
@@ -5973,27 +6139,13 @@
             },
           }],
         ],
-      },
-    }],
-    ['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',
+        'msvs_settings': {
+          'VCLinkerTool': {
+            'AdditionalOptions': [
+              '/opt:lldlto=1',
             ],
-          }],
-          ['_toolset=="target" and _type!="static_library"', {
-            'xcode_settings':  {
-              'OTHER_LDFLAGS': [
-                '-Wl,-mcpu,corei7-avx',
-              ],
-            },
-          }],
-        ],
+          },
+        },
       },
     }],
     ['use_lto==1 and clang==1 and target_arch=="arm"', {
@@ -6032,97 +6184,126 @@
         ],
       },
     }],
+    ['cfi_diag==1', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'cflags': [
+              '-fno-sanitize-trap=cfi',
+              '-fsanitize-recover=cfi',
+            ],
+            'cflags_cc!': [
+              '-fno-rtti',
+            ],
+            'cflags!': [
+              '-fno-rtti',
+            ],
+            'ldflags': [
+              '-fno-sanitize-trap=cfi',
+              '-fsanitize-recover=cfi',
+            ],
+            'xcode_settings': {
+              'OTHER_CFLAGS': [
+                '-fno-sanitize-trap=cfi',
+                '-fsanitize-recover=cfi',
+              ],
+            },
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  '-fno-sanitize-trap=cfi',
+                  '-fsanitize-recover=cfi',
+                ],
+              },
+            },
+          }],
+          ['_toolset=="target" and _type!="static_library"', {
+            'xcode_settings':  {
+              'OTHER_LDFLAGS': [
+                '-fno-sanitize-trap=cfi',
+                '-fsanitize-recover=cfi',
+              ],
+            },
+          }],
+        ],
+      },
+    }],
+    ['cfi_vptr==1 and cfi_diag==0', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'defines': [
+              'CFI_ENFORCEMENT',
+            ],
+          }],
+        ],
+      },
+    }],
     ['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-vcall',
               '-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)',
             ],
+            'ldflags': [
+              '-fsanitize=cfi-vcall',
+              '-fsanitize=cfi-derived-cast',
+              '-fsanitize=cfi-unrelated-cast',
+            ],
             'xcode_settings': {
               'OTHER_CFLAGS': [
+                '-fsanitize=cfi-vcall',
+                '-fsanitize=cfi-derived-cast',
+                '-fsanitize=cfi-unrelated-cast',
                 '-fsanitize-blacklist=<(cfi_blacklist)',
               ],
             },
           }],
+          ['_toolset=="target" and _type!="static_library"', {
+            'xcode_settings':  {
+              'OTHER_LDFLAGS': [
+                '-fsanitize=cfi-vcall',
+                '-fsanitize=cfi-derived-cast',
+                '-fsanitize=cfi-unrelated-cast',
+              ],
+            },
+          }],
+        ],
+      },
+    }],
+    ['cfi_vptr==1 and OS=="win"', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  # TODO(pcc): Use regular -fsanitize=* flags here once clang-cl
+                  # supports LTO.
+                  '-Xclang',
+                  '-fsanitize=cfi-vcall',
+                  '-Xclang',
+                  '-fsanitize=cfi-derived-cast',
+                  '-Xclang',
+                  '-fsanitize=cfi-unrelated-cast',
+                  '-Xclang',
+                  '-fsanitize-trap=cfi-vcall',
+                  '-Xclang',
+                  '-fsanitize-trap=cfi-derived-cast',
+                  '-Xclang',
+                  '-fsanitize-trap=cfi-unrelated-cast',
+                  '-Xclang',
+                  '-fsanitize-blacklist=<(cfi_blacklist)',
+                  '-Xclang',
+                  '-fsanitize-blacklist=../../<(make_clang_dir)/lib/clang/<!(python <(DEPTH)/tools/clang/scripts/update.py --print-clang-version)/cfi_blacklist.txt',
+                ],
+              },
+            },
+          }],
         ],
       },
     }],
diff --git a/build/compiled_action.gni b/build/compiled_action.gni
index b6d0c4d..855df7a 100644
--- a/build/compiled_action.gni
+++ b/build/compiled_action.gni
@@ -81,19 +81,19 @@
          "compiled_action doesn't take a sources arg. Use inputs instead.")
 
   action(target_name) {
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
-    }
+    deps = []
+    inputs = []
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "inputs",
+                             "outputs",
+                             "testonly",
+                             "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)"
 
@@ -109,12 +109,7 @@
     # Add the executable itself as an input.
     inputs += [ host_executable ]
 
-    deps = [
-      host_tool,
-    ]
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
+    deps += [ host_tool ]
 
     # The script takes as arguments the binary to run, and then the arguments
     # to pass it.
@@ -129,20 +124,19 @@
   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
-    }
+    deps = []
+    inputs = []
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "inputs",
+                             "outputs",
+                             "sources",
+                             "testonly",
+                             "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)"
@@ -159,12 +153,7 @@
     # Add the executable itself as an input.
     inputs += [ host_executable ]
 
-    deps = [
-      host_tool,
-    ]
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
+    deps += [ host_tool ]
 
     # The script takes as arguments the binary to run, and then the arguments
     # to pass it.
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index 5eb5e0a..596f9c4 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -6,14 +6,21 @@
 import("//build/config/chrome_build.gni")
 import("//build/config/crypto.gni")
 import("//build/config/features.gni")
+import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/ui.gni")
-import("//build/module_args/v8.gni")
+import("//build/toolchain/goma.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
+  # When set (the default) enables C++ iterator debugging in debug builds.
+  # Iterator debugging is always off in release builds (technically, this flag
+  # affects the "debug" config, which is always available but applied by
+  # default only in debug builds).
+  #
+  # Iterator debugging is generally useful for catching bugs. But it can
+  # introduce extra locking to check the state of an iterator against the state
+  # of the current object. For iterator- and thread-heavy code, this can
+  # significantly slow execution.
+  enable_iterator_debugging = true
 
   # 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
@@ -28,9 +35,6 @@
 
   # 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
@@ -42,11 +46,10 @@
 # For now we define these globally to match the current GYP build.
 config("feature_flags") {
   # TODO(brettw) this probably needs to be parameterized.
-  defines = [ "V8_DEPRECATION_WARNINGS" ]  # Don't use deprecated V8 APIs anywhere.
-
-  if (cld_version > 0) {
-    defines += [ "CLD_VERSION=$cld_version" ]
-  }
+  defines = [
+    "V8_DEPRECATION_WARNINGS",  # Don't use deprecated V8 APIs anywhere.
+    "CLD_VERSION=$cld_version",
+  ]
   if (enable_mdns) {
     defines += [ "ENABLE_MDNS=1" ]
   }
@@ -64,6 +67,9 @@
   if (enable_plugins) {
     defines += [ "ENABLE_PLUGINS=1" ]
   }
+  if (enable_pdf) {
+    defines += [ "ENABLE_PDF=1" ]
+  }
   if (enable_basic_printing || enable_print_preview) {
     # Convenience define for ENABLE_BASIC_PRINTING || ENABLE_PRINT_PREVIEW.
     defines += [ "ENABLE_PRINTING=1" ]
@@ -80,6 +86,9 @@
   if (enable_spellcheck) {
     defines += [ "ENABLE_SPELLCHECK=1" ]
   }
+  if (use_browser_spellchecker) {
+    defines += [ "USE_BROWSER_SPELLCHECKER=1" ]
+  }
   if (dont_embed_build_metadata) {
     defines += [ "DONT_EMBED_BUILD_METADATA" ]
   }
@@ -90,9 +99,6 @@
     # 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" ]
@@ -136,19 +142,37 @@
   if (use_allocator != "tcmalloc") {
     defines += [ "NO_TCMALLOC" ]
   }
-  if (is_asan) {
+  if (is_asan || is_lsan || is_tsan || is_msan) {
     defines += [
-      "ADDRESS_SANITIZER",
       "MEMORY_TOOL_REPLACES_ALLOCATOR",
       "MEMORY_SANITIZER_INITIAL_SIZE",
     ]
   }
+  if (is_asan) {
+    defines += [ "ADDRESS_SANITIZER" ]
+  }
+  if (is_lsan) {
+    defines += [
+      "LEAK_SANITIZER",
+      "WTF_USE_LEAK_SANITIZER=1",
+    ]
+  }
+  if (is_tsan) {
+    defines += [
+      "THREAD_SANITIZER",
+      "DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL=1",
+      "WTF_USE_DYNAMIC_ANNOTATIONS_NOIMPL=1",
+    ]
+  }
+  if (is_msan) {
+    defines += [ "MEMORY_SANITIZER" ]
+  }
+  if (is_ubsan || is_ubsan_vptr) {
+    defines += [ "UNDEFINED_SANITIZER" ]
+  }
   if (enable_webrtc) {
     defines += [ "ENABLE_WEBRTC=1" ]
   }
-  if (disable_ftp_support) {
-    defines += [ "DISABLE_FTP_SUPPORT=1" ]
-  }
   if (!enable_nacl) {
     defines += [ "DISABLE_NACL" ]
   }
@@ -191,39 +215,30 @@
   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 (enable_topchrome_md) {
+    defines += [ "ENABLE_TOPCHROME_MD=1" ]
+  }
+  if (enable_wayland_server) {
+    defines += [ "ENABLE_WAYLAND_SERVER=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" ]
   }
@@ -231,14 +246,8 @@
     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" ]
-  } else if (safe_browsing_mode == 3) {
-    defines += [ "MOBILE_SAFE_BROWSING" ]
     defines += [ "SAFE_BROWSING_DB_REMOTE" ]
-    defines += [ "SAFE_BROWSING_SERVICE" ]
   }
   if (is_official_build) {
     defines += [ "OFFICIAL_BUILD" ]
@@ -248,6 +257,22 @@
   } else {
     defines += [ "CHROMIUM_BUILD" ]
   }
+  if (enable_media_router) {
+    defines += [ "ENABLE_MEDIA_ROUTER=1" ]
+  }
+  if (enable_webvr) {
+    defines += [ "ENABLE_WEBVR" ]
+  }
+  if (is_syzyasan) {
+    defines += [
+      "SYZYASAN",
+      "MEMORY_TOOL_REPLACES_ALLOCATOR",
+      "MEMORY_SANITIZER_INITIAL_SIZE",
+    ]
+  }
+  if (!fieldtrial_testing_like_official_build && !is_chrome_branded) {
+    defines += [ "FIELDTRIAL_TESTING_ENABLED" ]
+  }
 }
 
 # Debug/release ----------------------------------------------------------------
@@ -264,13 +289,12 @@
   }
 
   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.
+    if (!enable_iterator_debugging) {
+      # Iterator debugging is enabled by default 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) {
+  } else if (is_linux && current_cpu == "x64" && enable_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?
@@ -284,7 +308,12 @@
   # Sanitizers.
   # TODO(GYP) The GYP build has "release_valgrind_build == 0" for this
   # condition. When Valgrind is set up, we need to do the same here.
-  if (!is_tsan) {
+  if (is_tsan) {
+    defines += [
+      "DYNAMIC_ANNOTATIONS_ENABLED=1",
+      "WTF_USE_DYNAMIC_ANNOTATIONS=1",
+    ]
+  } else {
     defines += [ "NVALGRIND" ]
     if (!is_nacl) {
       # NaCl always enables dynamic annotations. Currently this value is set to
@@ -353,17 +382,58 @@
       "CoreFoundation.framework",
       "Foundation.framework",
       "IOKit.framework",
+      "OpenGL.framework",
       "Security.framework",
     ]
   } else if (is_ios) {
+    # The libraries listed here will be specified for both the target and the
+    # host. Only the common ones should be listed here.
     libs = [
       "CoreFoundation.framework",
       "CoreGraphics.framework",
       "CoreText.framework",
       "Foundation.framework",
-      "UIKit.framework",
     ]
   } else if (is_linux) {
     libs = [ "dl" ]
   }
 }
+
+# Add this config to your target to enable precompiled headers.
+#
+# Precompiled headers are done on a per-target basis. If you have just a couple
+# of files, the time it takes to precompile (~2 seconds) can actually be longer
+# than the time saved. On a Z620, a 100 file target compiles about 2 seconds
+# faster with precompiled headers, with greater savings for larger targets.
+#
+# Recommend precompiled headers for targets with more than 50 .cc files.
+config("precompiled_headers") {
+  if (is_win && !is_official_build && !use_goma) {
+    # This is a string rather than a file GN knows about. It has to match
+    # exactly what's in the /FI flag below, and what might appear in the source
+    # code in quotes for an #include directive.
+    precompiled_header = "build/precompile.h"
+
+    # This is a file that GN will compile with the above header. It will be
+    # implicitly added to the sources (potentially multiple times, with one
+    # variant for each language used in the target).
+    precompiled_source = "//build/precompile.cc"
+
+    # Force include the header.
+    cflags = [ "/FI$precompiled_header" ]
+
+    # Disable warning for "this file was empty after preprocessing". This
+    # error is generated only in C mode for ANSI compatibility. It conflicts
+    # with precompiled headers since the source file that's "compiled" for
+    # making the precompiled header is empty.
+    #
+    # This error doesn't happen every time. In VS2013, it seems if the .pch
+    # file doesn't exist, no error will be generated (probably MS tested this
+    # case but forgot the other one?). To reproduce this error, do a build,
+    # then delete the precompile.c.obj file, then build again.
+    cflags_c = [ "/wd4206" ]
+  } else if (is_mac && !is_official_build && !use_goma) {
+    precompiled_header = "build/precompile.h"
+    precompiled_source = "//build/precompile.h"
+  }
+}
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index ee32088..3eed120 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -3,19 +3,36 @@
 # found in the LICENSE file.
 
 # =============================================================================
-# BUILD FLAGS
+# PLATFORM SELECTION
 # =============================================================================
 #
-# 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.
+# There are two main things to set: "os" and "cpu". The "toolchain" is the name
+# of the GN thing that encodes combinations of these things.
 #
-# 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.
+# Users typically only set the variables "target_os" and "target_cpu" in "gn
+# args", the rest are set up by our build and internal to GN.
 #
-# 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.
+# There are three different types of each of these things: The "host"
+# represents the computer doing the compile and never changes. The "target"
+# represents the main thing we're trying to build. The "current" represents
+# which configuration is currently being defined, which can be either the
+# host, the target, or something completely different (like nacl). GN will
+# run the same build file multiple times for the different required
+# configuration in the same build.
+#
+# This gives the following variables:
+#  - host_os, host_cpu, host_toolchain
+#  - target_os, target_cpu, default_toolchain
+#  - current_os, current_cpu, current_toolchain.
+#
+# Note the default_toolchain isn't symmetrical (you would expect
+# target_toolchain). This is because the "default" toolchain is a GN built-in
+# concept, and "target" is something our build sets up that's symmetrical with
+# its GYP counterpart. Potentially the built-in default_toolchain variable
+# could be renamed in the future.
+#
+# When writing build files, to do something only for the host:
+#   if (current_toolchain == host_toolchain) { ...
 
 if (target_os == "") {
   target_os = host_os
@@ -40,15 +57,60 @@
   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
+# =============================================================================
+# BUILD FLAGS
+# =============================================================================
+#
+# This block lists input arguments to the build, along with their default
+# values.
+#
+# If a value is specified on the command line, it will overwrite the defaults
+# given in a declare_args block, otherwise the default will be used.
+#
+# YOU SHOULD ALMOST NEVER NEED TO ADD FLAGS TO THIS FILE. GN allows any file in
+# the build to declare build flags. If you need a flag for a single component,
+# you can just declare it in the corresponding BUILD.gn file. If you need a
+# flag in multiple components, there are a few options:
+#
+# - If your feature is a single target, say //components/foo, and the targets
+#   depending on foo need to have some define set if foo is enabled: (1) Write
+#   a declare_args block in foo's BUILD.gn file listing your enable_foo build
+#   flag. (2) Write a config in that file listing the define, and list that
+#   config in foo's public_configs. This will propagate that define to all the
+#   targets depending on foo. (3) When foo is not enabled, just make it expand
+#   to an empty group (or whatever's appropriate for the "off" state of your
+#   feature.
+#
+# - If a semi-random set of targets need to know about a define: (1) In the
+#   lowest level of the build that knows about this feature, add a declare_args
+#   block in the build file for your enable flag. (2) Write a config that adds
+#   a define conditionally based on that build flags. (3) Manually add that
+#   config to the "configs" applying to the targets that need the define.
+#
+# - If a semi-random set of targets need to know about the build flag (to do
+#   file inclusion or exclusion, more than just defines): (1) Write a .gni file
+#   in the lowest-level directory that knows about the feature. (2) Put the
+#   declare_args block with your build flag in that .gni file. (3) Import that
+#   .gni file from the BUILD.gn files that need the flag.
+#
+# Other advice:
+#
+# - Use boolean values when possible. If you need a default value that expands
+#   to some complex thing in the default case (like the location of the
+#   compiler which would be computed by a script), use a default value of -1 or
+#   the empty string. Outside of the declare_args block, conditionally expand
+#   the default value as necessary.
+#
+# - Use a name like "use_foo" or "is_foo" (whatever is more appropriate for
+#   your feature) rather than just "foo".
+#
+# - Write good comments directly above the declaration with no blank line.
+#   These comments will appear as documentation in "gn args --list".
+#
+# - Don't call exec_script inside declare_args. This will execute the script
+#   even if the value is overridden, which is wasteful. See first bullet.
 
+declare_args() {
   # Component build.
   is_component_build = false
 
@@ -56,43 +118,108 @@
   is_debug = true
 
   # Whether we're a traditional desktop unix.
-  is_desktop_linux = current_os == "linux" && current_os != "chromeos"
+  is_desktop_linux = current_os == "linux"
 
   # 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
+  # Allows the path to a custom target toolchain to be injected as a single
+  # argument, and set as the default toolchain.
+  custom_toolchain = ""
 
-  # 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
+  # DON'T ADD MORE FLAGS HERE. Read the comment above.
+}
 
-  # Compile for Address Sanitizer to find memory bugs.
-  is_asan = false
+# ==============================================================================
+# 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.
+#
+# We do this before anything else to make sure we complain about any
+# unsupported os/cpu combinations as early as possible.
 
-  # 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
+if (host_os == "linux") {
+  if (target_os != "linux") {
+    # TODO(dpranke) - is_clang normally applies only to the target
+    # build, and there is no way to indicate that you want to override
+    # it for both the target build *and* the host build. Do we need to
+    # support this?
+    host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
+  } else if (is_clang) {
+    host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
+  } else {
+    host_toolchain = "//build/toolchain/linux:$host_cpu"
   }
+} else if (host_os == "mac") {
+  host_toolchain = "//build/toolchain/mac:clang_$host_cpu"
+} else if (host_os == "win") {
+  # TODO(crbug.com/467159): win cross-compiles don't actually work yet, so
+  # use the target_cpu instead of the host_cpu.
+  if (is_clang) {
+    host_toolchain = "//build/toolchain/win:clang_$target_cpu"
+  } else {
+    host_toolchain = "//build/toolchain/win:$target_cpu"
+  }
+} else {
+  assert(false, "Unsupported host_os: $host_os")
+}
+
+_default_toolchain = ""
+
+if (target_os == "android") {
+  assert(host_os == "linux" || host_os == "mac",
+         "Android builds are only supported on Linux and Mac hosts.")
+  if (is_clang) {
+    _default_toolchain = "//build/toolchain/android:clang_$target_cpu"
+  } else {
+    _default_toolchain = "//build/toolchain/android:$target_cpu"
+  }
+} else if (target_os == "chromeos") {
+  assert(host_os == "linux",
+         "ChromeOS builds are only supported on Linux hosts.")
+  if (is_clang) {
+    _default_toolchain = "//build/toolchain/linux:clang_$target_cpu"
+  } else {
+    _default_toolchain = "//build/toolchain/linux:$target_cpu"
+  }
+} else if (target_os == "ios") {
+  _default_toolchain = "//build/toolchain/mac:ios_clang_arm"
+} else if (target_os == "linux") {
+  if (is_clang) {
+    _default_toolchain = "//build/toolchain/linux:clang_$target_cpu"
+  } else {
+    _default_toolchain = "//build/toolchain/linux:$target_cpu"
+  }
+} else if (target_os == "mac") {
+  assert(host_os == "mac", "Mac cross-compiles are unsupported.")
+  _default_toolchain = host_toolchain
+} else if (target_os == "win") {
+  # On windows we use the same toolchain for host and target by default.
+  assert(target_os == host_os, "Win cross-compiles only work on win hosts.")
+  if (is_clang) {
+    _default_toolchain = "//build/toolchain/win:clang_$target_cpu"
+  } else {
+    _default_toolchain = "//build/toolchain/win:$target_cpu"
+  }
+} else if (target_os == "winrt_81" || target_os == "winrt_81_phone" ||
+           target_os == "winrt_10") {
+  _default_toolchain = "//build/toolchain/win:winrt_$target_cpu"
+} else {
+  assert(false, "Unsupported target_os: $target_os")
+}
+
+# If a custom toolchain has been set in the args, set it as default. Otherwise,
+# set the default toolchain for the platform (if any).
+if (custom_toolchain != "") {
+  set_default_toolchain(custom_toolchain)
+} else if (_default_toolchain != "") {
+  set_default_toolchain(_default_toolchain)
 }
 
 # =============================================================================
@@ -113,7 +240,8 @@
 # aix or one of the BSDs. If you need to check these, just check the
 # current_os value directly.
 
-if (current_os == "win") {
+if (current_os == "win" || current_os == "winrt_81" ||
+    current_os == "winrt_81_phone" || current_os == "winrt_10") {
   is_android = false
   is_chromeos = false
   is_ios = false
@@ -213,6 +341,7 @@
     "*_win.h",
     "*_win_unittest.cc",
     "*\bwin/*",
+    "*.def",
     "*.rc",
   ]
 }
@@ -294,16 +423,6 @@
 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
 # =============================================================================
 #
@@ -320,19 +439,25 @@
   "//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:default_optimization",
+  "//build/config/compiler:default_symbols",
   "//build/config/compiler:no_rtti",
   "//build/config/compiler:runtime_library",
+  "//build/config/sanitizers:default_sanitizer_flags",
+  "//build/config/sanitizers:default_sanitizer_coverage_flags",
 ]
 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 (current_os == "winrt_81" || current_os == "winrt_81_phone" ||
+    current_os == "winrt_10") {
+  _native_compiler_configs += [ "//build/config/win:target_winrt" ]
+}
 if (is_posix) {
   _native_compiler_configs += [
     "//build/config/gcc:no_exceptions",
@@ -340,55 +465,24 @@
   ]
 }
 
-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_android) {
+  _native_compiler_configs +=
+      [ "//build/config/android:default_cygprofile_instrumentation" ]
 }
 
-if (is_clang) {
+if (is_clang && !is_nacl) {
   _native_compiler_configs += [
     "//build/config/clang:find_bad_constructs",
     "//build/config/clang:extra_warnings",
   ]
 }
 
-# Optimizations and debug checking.
+# Debug/release-related defines.
 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) {
@@ -428,7 +522,8 @@
   configs = _native_compiler_configs
 }
 
-# Shared library defaults (also for components in component mode).
+# Shared library and loadable module defaults (also for components in component
+# mode).
 _shared_library_configs =
     _native_compiler_configs + [ "//build/config:default_libs" ]
 if (is_win) {
@@ -444,6 +539,9 @@
 set_defaults("shared_library") {
   configs = _shared_library_configs
 }
+set_defaults("loadable_module") {
+  configs = _shared_library_configs
+}
 if (is_component_build) {
   set_defaults("component") {
     configs = _shared_library_configs
@@ -470,266 +568,23 @@
 }
 
 # ==============================================================================
-# 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) {
-  if (host_os == "linux") {
-    # 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"
-    }
-  } else if (host_os == "mac") {
-    host_toolchain = "//build/toolchain/mac:clang_$host_cpu"
-  } else {
-    assert(false, "Unknown host for android cross compile")
-  }
-  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_x64"
-  set_default_toolchain(host_toolchain)
-} else if (is_ios) {
-  host_toolchain = "//build/toolchain/mac:clang_x64"
-  set_default_toolchain("//build/toolchain/mac:clang_$current_cpu")
-} 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"
+  _component_mode = "shared_library"
 } else {
-  component_mode = "source_set"
+  _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
+  target(_component_mode, target_name) {
+    forward_variables_from(invoker, "*")
 
-      # 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
-      }
+    # All shared libraries must have the sanitizer deps to properly link in
+    # asan mode (this target will be empty in other cases).
+    if (!defined(deps)) {
+      deps = []
     }
-  } 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
-      }
-    }
+    deps += [ "//build/config/sanitizers:deps" ]
   }
 }
diff --git a/build/config/allocator.gni b/build/config/allocator.gni
index 4c9ae67..5b6d963 100644
--- a/build/config/allocator.gni
+++ b/build/config/allocator.gni
@@ -2,8 +2,10 @@
 # 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) {
+import("//build/config/sanitizers/sanitizers.gni")
+
+if (is_android || current_cpu == "mipsel" || is_mac || is_ios || is_asan ||
+    is_lsan || is_tsan || is_msan || is_win || is_syzyasan) {
   _default_allocator = "none"
 } else {
   _default_allocator = "tcmalloc"
@@ -13,3 +15,7 @@
   # Memory allocator to use. Set to "none" to use default allocator.
   use_allocator = _default_allocator
 }
+
+assert(use_allocator == "none" || use_allocator == "tcmalloc")
+
+assert(!is_win || use_allocator == "none", "Tcmalloc doesn't work on Windows.")
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
index 5492693..cfbde79 100644
--- a/build/config/android/BUILD.gn
+++ b/build/config/android/BUILD.gn
@@ -3,26 +3,200 @@
 # found in the LICENSE file.
 
 import("//build/config/android/config.gni")
+import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/sysroot.gni")
 
-config("sdk") {
-  if (sysroot != "") {
-    cflags = [ "--sysroot=" + sysroot ]
-    ldflags = [ "--sysroot=" + sysroot ]
+assert(is_android)
 
-    # 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") ]
+# This is included by reference in the //build/config/compiler config that
+# is applied to all targets. It is here to separate out the logic that is
+# Android-only.
+config("compiler") {
+  cflags = [
+    "-ffunction-sections",
+    "-funwind-tables",
+    "-fno-short-enums",
+  ]
+  defines = [
+    "ANDROID",
+
+    # 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 = []
+
+  if (!is_clang) {
+    # Clang doesn't support these flags.
+    cflags += [ "-finline-limit=64" ]
+  }
+  if (is_clang) {
+    rebased_android_toolchain_root =
+        rebase_path(android_toolchain_root, root_build_dir)
+    if (current_cpu == "mipsel") {
+      cflags += [
+        # TODO(gordanac) Enable integrated-as.
+        "-no-integrated-as",
+        "-B${rebased_android_toolchain_root}/bin",  # Else /usr/bin/as gets picked up.
+      ]
+    }
+  }
+
+  # 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=$rebased_android_toolchain_root" ]
+    }
+
+    # Use -mstackrealign due to a bug on ia32 Jelly Bean.
+    # See crbug.com/521527
+    if (current_cpu == "x86") {
+      cflags += [ "-mstackrealign" ]
+    }
+  }
+
+  if (current_cpu == "mipsel" && is_clang) {
+    # Let clang find the ld.bfd in the NDK.
+    ldflags += [ "--gcc-toolchain=$rebased_android_toolchain_root" ]
+  }
+
+  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") {
+      abi_target = "arm-linux-androideabi"
+    } else if (current_cpu == "x86") {
+      abi_target = "i686-linux-androideabi"
+    } else if (current_cpu == "arm64") {
+      # Place holder for arm64 support, not tested.
+      # TODO: Enable clang support for Android Arm64. http://crbug.com/539781
+      abi_target = "aarch64-linux-androideabi"
+    } else if (current_cpu == "x64") {
+      # Place holder for x64 support, not tested.
+      # TODO: Enable clang support for Android x64. http://crbug.com/539781
+      abi_target = "x86_64-linux-androideabi"
+    } else if (current_cpu == "mipsel") {
+      abi_target = "mipsel-linux-android"
+    } else if (current_cpu == "mips64el") {
+      # Place holder for mips64 support, not tested.
+      abi_target = "mips64el-linux-androideabi"
+    } else {
+      assert(false, "Architecture not supported")
+    }
+    cflags += [
+      "-target",
+      abi_target,
+    ]
+    ldflags += [
+      "-target",
+      abi_target,
+    ]
+  }
+
+  # Assign any flags set for the C compiler to asmflags so that they are sent
+  # to the assembler.
+  asmflags = cflags
+}
+
+# This is included by reference in the //build/config/compiler:runtime_library
+# config that is applied to all targets. It is here to separate out the logic
+# that is Android-only. Please see that target for advice on what should go in
+# :runtime_library vs. :compiler.
+config("runtime_library") {
+  # 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.
+  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),
+  ]
+
+  defines = [ "__GNU_SOURCE=1" ]  # Necessary for clone().
+  ldflags = [ "-nostdlib" ]
+  lib_dirs = [ "$android_libcpp_root/libs/$android_app_abi" ]
+
+  # The libc++ runtime library (must come first).
+  if (is_component_build) {
+    libs = [ "c++_shared" ]
+  } else {
+    libs = [ "c++_static" ]
+  }
+
+  # libgcc must come before libdl for ld.bfd (MIPS)
+  if (current_cpu == "mipsel") {
+    libs += [
+      # ld linker is used for mips Android, and ld does not accept library
+      # absolute path prefixed by "-l"; Since libgcc does not exist in mips
+      # sysroot the proper library will be linked.
+      # TODO(gordanac): Remove once gold linker is used for mips Android.
+      "gcc",
+    ]
+  } else {
+    libs += [
+      # 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),
+    ]
+  }
+
+  libs += [
+    "c",
+    "dl",
+    "m",
+  ]
+
+  if (is_clang) {
+    # Work around incompatibilities between bionic and clang headers.
+    defines += [
+      "__compiler_offsetof=__builtin_offsetof",
+      "nan=__builtin_nan",
+    ]
+  }
+
+  # 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" ]
+  }
+
+  # Clang with libc++ does not require an explicit atomic library reference.
+  if (!is_clang) {
+    libs += [ "atomic" ]
   }
 }
 
 config("executable_config") {
   cflags = [ "-fPIE" ]
+  asmflags = [ "-fPIE" ]
   ldflags = [ "-pie" ]
 }
 
@@ -30,3 +204,37 @@
   ldflags = [ "-Wl,--version-script=" +
               rebase_path("//build/android/android_no_jni_exports.lst") ]
 }
+
+# Instrumentation -------------------------------------------------------------
+#
+# The BUILDCONFIG file sets the "default_cygprofile_instrumentation" config on
+# targets by default. You can override whether the cygprofile instrumentation is
+# used on a per-target basis:
+#
+# configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
+# configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
+
+config("default_cygprofile_instrumentation") {
+  if (use_order_profiling) {
+    configs = [ ":cygprofile_instrumentation" ]
+  } else {
+    configs = [ ":no_cygprofile_instrumentation" ]
+  }
+}
+
+config("cygprofile_instrumentation") {
+  cflags = [
+    "-finstrument-functions",
+
+    # Allow mmx intrinsics to inline, so that the compiler can expand the intrinsics.
+    "-finstrument-functions-exclude-file-list=mmintrin.h",
+
+    # Avoid 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",
+  ]
+  defines = [ "CYGPROFILE_INSTRUMENTATION=1" ]
+}
+
+config("no_cygprofile_instrumentation") {
+}
diff --git a/build/config/android/OWNERS b/build/config/android/OWNERS
index 3759e93..39f58e9 100644
--- a/build/config/android/OWNERS
+++ b/build/config/android/OWNERS
@@ -1 +1 @@
-cjhopman@chromium.org
+agrieve@chromium.org
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 0e25a9a..01e1b7a 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -5,6 +5,9 @@
 # This file contains common system config stuff for the Android build.
 
 if (is_android) {
+  assert(rebase_path("//", root_build_dir) == "../../",
+         "Android output directory must be nested 2 levels within src/ (" +
+             "e.g.: out-gn/Debug). http://crbug.com/412935")
   has_chrome_android_internal =
       exec_script("//build/dir_exists.py",
                   [ rebase_path("//clank", root_build_dir) ],
@@ -16,8 +19,15 @@
 
   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"
+    default_android_sdk_version = "23"
+    default_android_sdk_build_tools_version = "23.0.1"
+  }
+
+  if (!defined(default_android_keystore_path)) {
+    default_android_keystore_path =
+        "//build/android/ant/chromium-debug.keystore"
+    default_android_keystore_name = "chromiumdebugkey"
+    default_android_keystore_password = "chromium"
   }
 
   if (!defined(google_play_services_library)) {
@@ -25,15 +35,24 @@
         "//third_party/android_tools:google_play_services_default_java"
   }
 
+  if (!defined(google_play_services_resources)) {
+    google_play_services_resources =
+        "//third_party/android_tools:google_play_services_default_resources"
+  }
+
   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"
+    # The path to the keystore to use for signing builds.
+    android_keystore_path = default_android_keystore_path
+
+    # The name of the keystore to use for signing builds.
+    android_keystore_name = default_android_keystore_name
+
+    # The password for the keystore to use for signing builds.
+    android_keystore_password = default_android_keystore_password
 
     # This is a unique identifier for a given build. It's used for
     # identifying various build artifacts corresponding to a particular build of
@@ -42,6 +61,42 @@
 
     # Set to true to run findbugs on JAR targets.
     run_findbugs = false
+
+    # Set to true to enable verbose findbugs logging. This does nothing if
+    # run_findbugs is false.
+    findbugs_verbose = false
+
+    # Set to true to enable the Errorprone compiler
+    use_errorprone_java_compiler = false
+
+    # Enables EMMA Java code coverage. Instruments classes during build to
+    # produce .ec files during runtime
+    emma_coverage = false
+
+    # EMMA filter string consisting of a list of inclusion/exclusion patterns
+    # separated with whitespace and/or comma. Only has effect if
+    # emma_coverage==true
+    emma_filter = ""
+
+    # Disables process isolation when building _incremental targets.
+    # Required for Android M+ due to SELinux policies (stronger sandboxing).
+    disable_incremental_isolated_processes = false
+
+    # Speed up incremental compiles by compiling only changed files.
+    enable_incremental_javac = false
+
+    # Speed up dexing using dx --incremental.
+    enable_incremental_dx = is_debug
+
+    # Neither of these should ever be used for release builds since they are
+    # somewhat experimental and dx --incremental is known to not produce
+    # byte-for-byte identical output.
+    assert(!(enable_incremental_dx && !is_debug))
+    assert(!(enable_incremental_javac && !is_debug))
+
+    # Adds intrumentation to each function. Writes a file with the order that
+    # functions are called at startup.
+    use_order_profiling = false
   }
 
   # Host stuff -----------------------------------------------------------------
@@ -91,7 +146,7 @@
 
   # Subdirectories inside android_ndk_root that contain the sysroot for the
   # associated platform.
-  _android_api_level = 14
+  _android_api_level = 16
   x86_android_sysroot_subdir =
       "platforms/android-${_android_api_level}/arch-x86"
   arm_android_sysroot_subdir =
@@ -159,13 +214,9 @@
   android_gdbserver =
       "$android_ndk_root/prebuilt/$android_prebuilt_arch/gdbserver/gdbserver"
 
-  # libc++ stuff ---------------------------------------------------------------
+  # Toolchain stuff ------------------------------------------------------------
 
-  if (component_mode == "shared_library") {
-    android_libcpp_library = "c++_shared"
-  } else {
-    android_libcpp_library = "c++_static"
-  }
+  android_libcpp_root = "$android_ndk_root/sources/cxx-stl/llvm-libc++"
 
   # ABI ------------------------------------------------------------------------
 
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 07a05e1..4f1e491 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -3,6 +3,9 @@
 # found in the LICENSE file.
 
 import("//build/config/android/config.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+import("//build/config/zip.gni")
+import("//third_party/ijar/ijar.gni")
 
 assert(is_android)
 
@@ -13,12 +16,15 @@
 
 android_sdk_jar = "$android_sdk/android.jar"
 rebased_android_sdk_jar = rebase_path(android_sdk_jar, root_build_dir)
+android_aapt_path = "$rebased_android_sdk_build_tools/aapt"
+
+android_configuration_name = "Release"
+if (is_debug) {
+  android_configuration_name = "Debug"
+}
 
 template("android_lint") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
 
   jar_path = invoker.jar_path
   android_manifest = invoker.android_manifest
@@ -26,6 +32,13 @@
   base_path = "$target_gen_dir/$target_name"
 
   action(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "data_deps",
+                             "public_deps",
+                             "testonly",
+                           ])
     script = "//build/android/gyp/lint.py"
     result_path = base_path + "/result.xml"
     config_path = base_path + "/config.xml"
@@ -62,12 +75,62 @@
   }
 }
 
+template("proguard") {
+  action(target_name) {
+    set_sources_assignment_filter([])
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "data_deps",
+                             "public_deps",
+                             "testonly",
+                           ])
+    script = "//build/android/gyp/proguard.py"
+    _proguard_jar_path = "//third_party/proguard/lib/proguard.jar"
+    _output_jar_path = invoker.output_jar_path
+    inputs = [
+      android_sdk_jar,
+      _proguard_jar_path,
+    ]
+    if (defined(invoker.inputs)) {
+      inputs += invoker.inputs
+    }
+    depfile = "${target_gen_dir}/${target_name}.d"
+    outputs = [
+      depfile,
+      _output_jar_path,
+      "$_output_jar_path.dump",
+      "$_output_jar_path.seeds",
+      "$_output_jar_path.mapping",
+      "$_output_jar_path.usage",
+    ]
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--proguard-path",
+      rebase_path(_proguard_jar_path, root_build_dir),
+      "--output-path",
+      rebase_path(_output_jar_path, root_build_dir),
+      "--classpath",
+      rebased_android_sdk_jar,
+    ]
+    if (defined(invoker.args)) {
+      args += invoker.args
+    }
+  }
+}
+
 template("findbugs") {
   jar_path = invoker.jar_path
 
   build_config = invoker.build_config
 
   action(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "testonly",
+                           ])
     script = "//build/android/findbugs_diff.py"
     depfile = "$target_gen_dir/$target_name.d"
     result_path = "$target_gen_dir/$target_name/result.xml"
@@ -97,33 +160,130 @@
       rebase_path(result_path, root_build_dir),
       rebase_path(jar_path, root_build_dir),
     ]
+
+    if (findbugs_verbose) {
+      args += [ "-vv" ]
+    }
+  }
+}
+
+# Generates a script in the output bin.java directory to run a java binary.
+#
+# Variables
+#   main_class: The class containing the progam entry point.
+#   jar_path: The path to the jar to run.
+#   script_name: Name of the script to generate.
+#   build_config: Path to .build_config for the jar (contains classpath).
+#   wrapper_script_args: List of extra arguments to pass to the executable.
+#
+template("java_binary_script") {
+  set_sources_assignment_filter([])
+  forward_variables_from(invoker, [ "testonly" ])
+
+  _main_class = invoker.main_class
+  _build_config = invoker.build_config
+  _jar_path = invoker.jar_path
+  _script_name = invoker.script_name
+
+  action(target_name) {
+    script = "//build/android/gyp/create_java_binary_script.py"
+    depfile = "$target_gen_dir/$_script_name.d"
+    java_script = "$root_build_dir/bin/$_script_name"
+    inputs = [
+      _build_config,
+    ]
+    outputs = [
+      depfile,
+      java_script,
+    ]
+    forward_variables_from(invoker, [ "deps" ])
+    _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",
+      _main_class,
+    ]
+    if (defined(invoker.wrapper_script_args)) {
+      args += [ "--" ] + invoker.wrapper_script_args
+    }
+    if (defined(invoker.bootclasspath)) {
+      args += [
+        "--bootclasspath",
+        invoker.bootclasspath,
+      ]
+    }
   }
 }
 
 template("dex") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
+
+  _enable_multidex = defined(invoker.enable_multidex) && invoker.enable_multidex
+
+  if (_enable_multidex) {
+    _main_dex_list_path = invoker.output + ".main_dex_list"
+    _main_dex_list_target_name = "${target_name}__main_dex_list"
+    action(_main_dex_list_target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "deps",
+                               "inputs",
+                               "sources",
+                               "testonly",
+                             ])
+
+      script = "//build/android/gyp/main_dex_list.py"
+      depfile = "$target_gen_dir/$target_name.d"
+
+      main_dex_rules = "//build/android/main_dex_classes.flags"
+
+      outputs = [
+        depfile,
+        _main_dex_list_path,
+      ]
+
+      args = [
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--android-sdk-tools",
+        rebased_android_sdk_build_tools,
+        "--main-dex-list-path",
+        rebase_path(_main_dex_list_path, root_build_dir),
+        "--main-dex-rules-path",
+        rebase_path(main_dex_rules, root_build_dir),
+      ]
+
+      if (defined(invoker.args)) {
+        args += invoker.args
+      }
+
+      if (defined(invoker.sources)) {
+        args += rebase_path(invoker.sources, root_build_dir)
+      }
+    }
   }
 
   assert(defined(invoker.output))
   action(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "inputs",
+                             "sources",
+                             "testonly",
+                           ])
     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)
 
@@ -136,10 +296,24 @@
       rebased_output,
     ]
 
+    if (enable_incremental_dx) {
+      args += [ "--incremental" ]
+    }
+
     if (defined(invoker.no_locals) && invoker.no_locals) {
       args += [ "--no-locals=1" ]
     }
 
+    if (_enable_multidex) {
+      args += [
+        "--multi-dex",
+        "--main-dex-list-path",
+        rebase_path(_main_dex_list_path, root_build_dir),
+      ]
+      deps += [ ":${_main_dex_list_target_name}" ]
+      inputs += [ _main_dex_list_path ]
+    }
+
     if (defined(invoker.args)) {
       args += invoker.args
     }
@@ -150,42 +324,6 @@
   }
 }
 
-# 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
@@ -196,30 +334,27 @@
 # 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) {
+    set_sources_assignment_filter([])
+    type = invoker.type
+    build_config = invoker.build_config
+
+    assert(type == "android_apk" || type == "java_library" ||
+           type == "android_resources" || type == "deps_dex" ||
+           type == "android_assets" || type == "resource_rewriter")
+
+    deps = []
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "testonly",
+                             "visibility",
+                           ])
+
     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")
@@ -246,15 +381,18 @@
 
     is_java_library = type == "java_library"
     is_apk = type == "android_apk"
+    is_android_assets = type == "android_assets"
     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)
+    supports_android =
+        is_apk || is_android_assets || is_android_resources || is_deps_dex ||
+        (is_java_library && defined(invoker.supports_android) &&
+         invoker.supports_android)
+    requires_android =
+        is_apk || is_android_assets || 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")
@@ -302,6 +440,27 @@
       ]
     }
 
+    if (is_android_assets) {
+      if (defined(invoker.asset_sources)) {
+        inputs += invoker.asset_sources
+        _rebased_asset_sources =
+            rebase_path(invoker.asset_sources, root_build_dir)
+        args += [ "--asset-sources=$_rebased_asset_sources" ]
+      }
+      if (defined(invoker.asset_renaming_sources)) {
+        inputs += invoker.asset_renaming_sources
+        _rebased_asset_renaming_sources =
+            rebase_path(invoker.asset_renaming_sources, root_build_dir)
+        args += [ "--asset-renaming-sources=$_rebased_asset_renaming_sources" ]
+
+        # These are zip paths, so no need to rebase.
+        args += [ "--asset-renaming-destinations=${invoker.asset_renaming_destinations}" ]
+      }
+      if (defined(invoker.disable_compression) && invoker.disable_compression) {
+        args += [ "--disable-asset-compression" ]
+      }
+    }
+
     if (is_android_resources || is_apk) {
       assert(defined(invoker.resources_zip))
       args += [
@@ -341,6 +500,19 @@
           "--readelf-path=$rebased_android_readelf",
         ]
       }
+
+      if (defined(invoker.proguard_enabled) && invoker.proguard_enabled) {
+        args += [
+          "--proguard-enabled",
+          "--proguard-info",
+          rebase_path(invoker.proguard_info, root_build_dir),
+        ]
+      }
+
+      if (defined(invoker.apk_path)) {
+        _rebased_apk_path = rebase_path(invoker.apk_path, root_build_dir)
+        args += [ "--apk-path=$_rebased_apk_path" ]
+      }
     }
 
     if (defined(invoker.srcjar)) {
@@ -354,53 +526,49 @@
 
 template("process_java_prebuilt") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(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"
+    _proguard_config_path = invoker.proguard_config
+    _output_jar_target = "${target_name}__proguard_process"
+    proguard(_output_jar_target) {
+      forward_variables_from(invoker,
+                             [
+                               "data_deps",
+                               "deps",
+                               "public_deps",
+                             ])
       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,
-      ]
+      output_jar_path = _output_jar_path
+      _rebased_input_paths = [ rebase_path(_input_jar_path, root_build_dir) ]
+      _rebased_proguard_configs =
+          [ rebase_path(_proguard_config_path, root_build_dir) ]
       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,
+        "--input-paths=$_rebased_input_paths",
+        "--proguard-configs=$_rebased_proguard_configs",
         "--classpath=@FileArg($_rebased_build_config:javac:classpath)",
       ]
     }
   } else {
-    copy("${target_name}__copy_jar") {
+    _output_jar_target = "${target_name}__copy_jar"
+    copy(_output_jar_target) {
+      forward_variables_from(invoker,
+                             [
+                               "data_deps",
+                               "deps",
+                               "public_deps",
+                             ])
       sources = [
         _input_jar_path,
       ]
@@ -410,180 +578,208 @@
     }
   }
 
-  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",
+    forward_variables_from(invoker, [ "visibility" ])
+    public_deps = [
+      ":$_output_jar_target",
     ]
   }
 }
 
-# Packages resources, assets, dex, and native libraries into an apk. Signs and
-# zipaligns the apk.
-template("create_apk") {
+template("emma_instr") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(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
+  assert(invoker.source_files != [] || true)  # Mark as used
 
-  _deps = []
-  if (defined(invoker.deps)) {
-    _deps = invoker.deps
-  }
+  if (invoker.emma_instrument) {
+    _output_jar_target = "${target_name}__process"
+    _coverage_file = "$target_out_dir/${target_name}.em"
+    _source_dirs_listing_file = "$target_out_dir/${target_name}_sources.txt"
+    _emma_jar = "${android_sdk_root}/tools/lib/emma.jar"
+    _rebased_source_files = rebase_path(invoker.source_files, root_build_dir)
+    action(_output_jar_target) {
+      forward_variables_from(invoker, [ "deps" ])
 
-  _native_libs_dir = "//build/android/empty/res"
-  if (defined(invoker.native_libs_dir)) {
-    _native_libs_dir = invoker.native_libs_dir
-  }
+      script = "//build/android/gyp/emma_instr.py"
+      depfile = "${target_gen_dir}/${target_name}.d"
+      inputs = [
+        _emma_jar,
+        invoker.input_jar_path,
+      ]
+      outputs = [
+        depfile,
+        _coverage_file,
+        _source_dirs_listing_file,
+        invoker.output_jar_path,
+      ]
+      args = [
+        "instrument_jar",
+        "--input-path",
+        rebase_path(invoker.input_jar_path, root_build_dir),
+        "--output-path",
+        rebase_path(invoker.output_jar_path, root_build_dir),
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--coverage-file",
+        rebase_path(_coverage_file, root_build_dir),
+        "--sources-list-file",
+        rebase_path(_source_dirs_listing_file, root_build_dir),
+        "--source-files=$_rebased_source_files",
+        "--src-root",
+        rebase_path("//", root_build_dir),
+        "--emma-jar",
+        rebase_path(_emma_jar, root_build_dir),
+        "--filter-string",
+        emma_filter,
+      ]
+    }
+  } else {
+    _output_jar_target = "${target_name}__copy_jar"
+    copy(_output_jar_target) {
+      forward_variables_from(invoker, [ "deps" ])
 
-  _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" ]
+      sources = [
+        invoker.input_jar_path,
+      ]
+      outputs = [
+        invoker.output_jar_path,
+      ]
     }
   }
 
-  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,
+  group(target_name) {
+    forward_variables_from(invoker, [ "visibility" ])
+    public_deps = [
+      ":$_output_jar_target",
     ]
+  }
+}
+
+# Creates an unsigned .apk.
+#
+# Variables
+#   assets_build_config: Path to android_apk .build_config containing merged
+#       asset information.
+#   deps: Specifies the dependencies of this target.
+#   dex_path: Path to classes.dex file to include (optional).
+#   resource_packaged_apk_path: Path to .ap_ to use.
+#   output_apk_path: Output path for the generated .apk.
+#   native_lib_placeholders: List of placeholder filenames to add to the apk
+#     (optional).
+#   native_libs: List of native libraries.
+#   native_libs_filearg: @FileArg() of additionaly native libraries.
+#   write_asset_list: Adds an extra file to the assets, which contains a list of
+#     all other asset files.
+template("package_apk") {
+  action(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "public_deps",
+                             "testonly",
+                           ])
+    _native_lib_placeholders = []
+    if (defined(invoker.native_lib_placeholders)) {
+      _native_lib_placeholders = invoker.native_lib_placeholders
+    }
+
+    script = "//build/android/gyp/apkbuilder.py"
+    depfile = "$target_gen_dir/$target_name.d"
+    data_deps = [
+      "//tools/android/md5sum",
+    ]  # Used when deploying APKs
+
+    inputs = invoker.native_libs + [ invoker.resource_packaged_apk_path ]
+    if (defined(invoker.dex_path)) {
+      inputs += [ invoker.dex_path ]
+    }
 
     outputs = [
       depfile,
-      _packaged_apk_path,
+      invoker.output_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)
+        rebase_path(invoker.resource_packaged_apk_path, root_build_dir)
+    _rebased_packaged_apk_path =
+        rebase_path(invoker.output_apk_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),
+      "--resource-apk=$_rebased_resource_packaged_apk_path",
+      "--output-apk=$_rebased_packaged_apk_path",
     ]
-  }
+    if (defined(invoker.assets_build_config)) {
+      inputs += [ invoker.assets_build_config ]
+      _rebased_build_config =
+          rebase_path(invoker.assets_build_config, root_build_dir)
+      args += [
+        "--assets=@FileArg($_rebased_build_config:assets)",
+        "--uncompressed-assets=@FileArg($_rebased_build_config:uncompressed_assets)",
+      ]
+    }
+    if (defined(invoker.write_asset_list) && invoker.write_asset_list) {
+      args += [ "--write-asset-list" ]
+    }
+    if (defined(invoker.dex_path)) {
+      _rebased_dex_path = rebase_path(invoker.dex_path, root_build_dir)
+      args += [ "--dex-file=$_rebased_dex_path" ]
+    }
+    if (invoker.native_libs != [] || defined(invoker.native_libs_filearg) ||
+        _native_lib_placeholders != []) {
+      args += [ "--android-abi=$android_app_abi" ]
+    }
+    if (invoker.native_libs != []) {
+      _rebased_native_libs = rebase_path(invoker.native_libs, root_build_dir)
+      args += [ "--native-libs=$_rebased_native_libs" ]
+    }
+    if (defined(invoker.native_libs_filearg)) {
+      args += [ "--native-libs=${invoker.native_libs_filearg}" ]
+    }
+    if (_native_lib_placeholders != []) {
+      args += [ "--native-lib-placeholders=$_native_lib_placeholders" ]
+    }
 
-  action("${target_name}__finalize") {
+    if (defined(invoker.emma_instrument) && invoker.emma_instrument) {
+      _emma_device_jar = "$android_sdk_root/tools/lib/emma_device.jar"
+      _rebased_emma_device_jar = rebase_path(_emma_device_jar, root_build_dir)
+      args += [ "--emma-device-jar=$_rebased_emma_device_jar" ]
+    }
+  }
+}
+
+# Signs & zipaligns an apk.
+#
+# Variables
+#   input_apk_path: Path of the .apk to be finalized.
+#   output_apk_path: Output path for the generated .apk.
+#   keystore_path: Path to keystore to use for signing.
+#   keystore_name: Key alias to use.
+#   keystore_password: Keystore password.
+#   rezip_apk: Whether to add crazy-linker alignment.
+template("finalize_apk") {
+  action(target_name) {
+    deps = []
     script = "//build/android/gyp/finalize_apk.py"
     depfile = "$target_gen_dir/$target_name.d"
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "data_deps",
+                             "public_deps",
+                             "testonly",
+                           ])
 
     sources = [
-      _packaged_apk_path,
+      invoker.input_apk_path,
     ]
     inputs = [
-      _keystore_path,
+      invoker.keystore_path,
     ]
     outputs = [
       depfile,
-      _final_apk_path,
+      invoker.output_apk_path,
     ]
 
     args = [
@@ -592,65 +788,406 @@
       "--zipalign-path",
       rebase_path(zipalign_path, root_build_dir),
       "--unsigned-apk-path",
-      rebase_path(_packaged_apk_path, root_build_dir),
+      rebase_path(invoker.input_apk_path, root_build_dir),
       "--final-apk-path",
-      rebase_path(_final_apk_path, root_build_dir),
+      rebase_path(invoker.output_apk_path, root_build_dir),
       "--key-path",
-      rebase_path(_keystore_path, root_build_dir),
+      rebase_path(invoker.keystore_path, root_build_dir),
       "--key-name",
-      _keystore_name,
+      invoker.keystore_name,
       "--key-passwd",
-      _keystore_password,
+      invoker.keystore_password,
     ]
-    if (_load_library_from_apk) {
+    if (defined(invoker.rezip_apk) && invoker.rezip_apk) {
+      deps += [ "//build/android/rezip" ]
       _rezip_jar_path = "$root_build_dir/lib.java/rezip_apk.jar"
-      inputs += [ _rezip_jar_path ]
       args += [
-        "--load-library-from-zip-file=1",
+        "--load-library-from-zip=1",
         "--rezip-apk-jar-path",
         rebase_path(_rezip_jar_path, root_build_dir),
       ]
     }
   }
+}
+
+# Packages resources, assets, dex, and native libraries into an apk. Signs and
+# zipaligns the apk.
+template("create_apk") {
+  set_sources_assignment_filter([])
+  forward_variables_from(invoker, [ "testonly" ])
+
+  _android_manifest = invoker.android_manifest
+  _base_path = invoker.base_path
+  _final_apk_path = invoker.apk_path
+  _incremental_final_apk_path_helper =
+      process_file_template(
+          [ _final_apk_path ],
+          "{{source_dir}}/{{source_name_part}}_incremental.apk")
+  _incremental_final_apk_path = _incremental_final_apk_path_helper[0]
+
+  if (defined(invoker.resources_zip)) {
+    _resources_zip = invoker.resources_zip
+    assert(_resources_zip != "")  # Mark as used.
+  }
+  if (defined(invoker.dex_path)) {
+    _dex_path = invoker.dex_path
+  }
+  _load_library_from_apk = invoker.load_library_from_apk
+
+  _deps = []
+  if (defined(invoker.deps)) {
+    _deps = invoker.deps
+  }
+  _incremental_deps = []
+  if (defined(invoker.incremental_deps)) {
+    _incremental_deps = invoker.incremental_deps
+  }
+  _native_libs = []
+  if (defined(invoker.native_libs)) {
+    _native_libs = invoker.native_libs
+  }
+  _native_libs_even_when_incremental = []
+  if (defined(invoker.native_libs_even_when_incremental)) {
+    _native_libs_even_when_incremental =
+        invoker.native_libs_even_when_incremental
+  }
+
+  # TODO(agrieve): Remove support for asset_location in favor of using
+  # android_assets() everywhere (http://crbug.com/547162).
+  if (defined(invoker.asset_location)) {
+    _asset_location = invoker.asset_location
+    assert(_asset_location != "")  # Mark as used.
+  }
+
+  _version_code = invoker.version_code
+  _version_name = invoker.version_name
+  assert(_version_code != -1)  # Mark as used.
+  assert(_version_name != "")  # Mark as used.
+
+  _base_apk_path = _base_path + ".apk_intermediates"
+
+  _resource_packaged_apk_path = _base_apk_path + ".ap_"
+  _incremental_resource_packaged_apk_path = _base_apk_path + "_incremental.ap_"
+  _packaged_apk_path = _base_apk_path + ".unfinished.apk"
+  _incremental_packaged_apk_path =
+      _base_apk_path + "_incremental.unfinished.apk"
+  _shared_resources =
+      defined(invoker.shared_resources) && invoker.shared_resources
+  assert(_shared_resources || true)  # Mark as used.
+
+  _keystore_path = invoker.keystore_path
+  _keystore_name = invoker.keystore_name
+  _keystore_password = invoker.keystore_password
+
+  _split_densities = []
+  if (defined(invoker.create_density_splits) && invoker.create_density_splits) {
+    _split_densities = [
+      "hdpi",
+      "xhdpi",
+      "xxhdpi",
+      "xxxhdpi",
+      "tvdpi",
+    ]
+  }
+
+  _split_languages = []
+  if (defined(invoker.language_splits)) {
+    _split_languages = invoker.language_splits
+  }
+
+  template("package_resources_helper") {
+    action(target_name) {
+      deps = invoker.deps
+
+      script = "//build/android/gyp/package_resources.py"
+      depfile = "${target_gen_dir}/${target_name}.d"
+      inputs = [
+        invoker.android_manifest,
+      ]
+      if (defined(_resources_zip)) {
+        inputs += [ _resources_zip ]
+      }
+      outputs = [
+        depfile,
+        invoker.resource_packaged_apk_path,
+      ]
+
+      args = [
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--android-sdk",
+        rebased_android_sdk,
+        "--aapt-path",
+        android_aapt_path,
+        "--configuration-name=$android_configuration_name",
+        "--android-manifest",
+        rebase_path(invoker.android_manifest, root_build_dir),
+        "--version-code",
+        _version_code,
+        "--version-name",
+        _version_name,
+        "--apk-path",
+        rebase_path(invoker.resource_packaged_apk_path, root_build_dir),
+      ]
+
+      if (defined(_asset_location)) {
+        args += [
+          "--asset-dir",
+          rebase_path(_asset_location, root_build_dir),
+        ]
+      }
+      if (defined(_resources_zip)) {
+        args += [
+          "--resource-zips",
+          rebase_path(_resources_zip, root_build_dir),
+        ]
+      }
+      if (_shared_resources) {
+        args += [ "--shared-resources" ]
+      }
+      if (_split_densities != []) {
+        args += [ "--create-density-splits" ]
+        foreach(_density, _split_densities) {
+          outputs += [ "${invoker.resource_packaged_apk_path}_${_density}" ]
+        }
+      }
+      if (_split_languages != []) {
+        args += [ "--language-splits=$_split_languages" ]
+        foreach(_language, _split_languages) {
+          outputs += [ "${invoker.resource_packaged_apk_path}_${_language}" ]
+        }
+      }
+      if (defined(invoker.extensions_to_not_compress)) {
+        args += [
+          "--no-compress",
+          invoker.extensions_to_not_compress,
+        ]
+      }
+    }
+  }
+
+  _package_resources_target_name = "${target_name}__package_resources"
+  package_resources_helper(_package_resources_target_name) {
+    forward_variables_from(invoker, [ "extensions_to_not_compress" ])
+    deps = _deps
+    android_manifest = _android_manifest
+    resource_packaged_apk_path = _resource_packaged_apk_path
+  }
+
+  _generate_incremental_manifest_target_name =
+      "${target_name}_incremental_generate_manifest"
+  _incremental_android_manifest =
+      get_label_info(_generate_incremental_manifest_target_name,
+                     "target_gen_dir") + "/AndroidManifest.xml"
+  action(_generate_incremental_manifest_target_name) {
+    deps = _incremental_deps
+    script = "//build/android/incremental_install/generate_android_manifest.py"
+    depfile = "${target_gen_dir}/${target_name}.d"
+    inputs = [
+      _android_manifest,
+    ]
+    outputs = [
+      depfile,
+      _incremental_android_manifest,
+    ]
+
+    _rebased_src_manifest = rebase_path(_android_manifest, root_build_dir)
+    _rebased_incremental_manifest =
+        rebase_path(_incremental_android_manifest, root_build_dir)
+    _rebased_depfile = rebase_path(depfile, root_build_dir)
+    args = [
+      "--src-manifest=$_rebased_src_manifest",
+      "--out-manifest=$_rebased_incremental_manifest",
+      "--depfile=$_rebased_depfile",
+    ]
+    if (disable_incremental_isolated_processes) {
+      args += [ "--disable-isolated-processes" ]
+    }
+  }
+
+  _incremental_package_resources_target_name =
+      "${target_name}_incremental__package_resources"
+
+  # TODO(agrieve): See if we can speed up this step by swapping the manifest
+  # from the result of the main package_resources step.
+  package_resources_helper(_incremental_package_resources_target_name) {
+    forward_variables_from(invoker, [ "extensions_to_not_compress" ])
+    deps =
+        _incremental_deps + [ ":$_generate_incremental_manifest_target_name" ]
+    android_manifest = _incremental_android_manifest
+    resource_packaged_apk_path = _incremental_resource_packaged_apk_path
+  }
+
+  package_target = "${target_name}__package"
+  package_apk(package_target) {
+    forward_variables_from(invoker,
+                           [
+                             "assets_build_config",
+                             "emma_instrument",
+                             "native_lib_placeholders",
+                             "native_libs_filearg",
+                             "write_asset_list",
+                           ])
+    deps = _deps + [ ":${_package_resources_target_name}" ]
+    native_libs = _native_libs + _native_libs_even_when_incremental
+
+    if (defined(_dex_path)) {
+      dex_path = _dex_path
+    }
+
+    output_apk_path = _packaged_apk_path
+    resource_packaged_apk_path = _resource_packaged_apk_path
+  }
+
+  _incremental_package_target = "${target_name}_incremental__package"
+  package_apk(_incremental_package_target) {
+    forward_variables_from(invoker,
+                           [
+                             "assets_build_config",
+                             "emma_instrument",
+                           ])
+    _dex_target = "//build/android/incremental_install:bootstrap_java__dex"
+    deps = _incremental_deps + [
+             ":${_incremental_package_resources_target_name}",
+             _dex_target,
+           ]
+
+    if (defined(_dex_path)) {
+      dex_path =
+          get_label_info(_dex_target, "target_gen_dir") + "/bootstrap.dex"
+    }
+
+    native_libs = _native_libs_even_when_incremental
+
+    # http://crbug.com/384638
+    _has_native_libs =
+        defined(invoker.native_libs_filearg) || _native_libs != []
+    if (_has_native_libs && _native_libs_even_when_incremental == []) {
+      native_lib_placeholders = [ "libfix.crbug.384638.so" ]
+    }
+
+    output_apk_path = _incremental_packaged_apk_path
+    resource_packaged_apk_path = _incremental_resource_packaged_apk_path
+  }
+
+  _finalize_apk_rule_name = "${target_name}__finalize"
+  finalize_apk(_finalize_apk_rule_name) {
+    input_apk_path = _packaged_apk_path
+    output_apk_path = _final_apk_path
+    keystore_path = _keystore_path
+    keystore_name = _keystore_name
+    keystore_password = _keystore_password
+    rezip_apk = _load_library_from_apk
+
+    public_deps = [
+      # Generator of the _packaged_apk_path this target takes as input.
+      ":$package_target",
+    ]
+  }
+
+  _incremental_finalize_apk_rule_name = "${target_name}_incremental__finalize"
+  finalize_apk(_incremental_finalize_apk_rule_name) {
+    input_apk_path = _incremental_packaged_apk_path
+    output_apk_path = _incremental_final_apk_path
+    keystore_path = _keystore_path
+    keystore_name = _keystore_name
+    keystore_password = _keystore_password
+
+    public_deps = [
+      ":$_incremental_package_target",
+    ]
+  }
+
+  _split_deps = []
+
+  template("finalize_split") {
+    finalize_apk(target_name) {
+      _config = invoker.split_config
+      _type = invoker.split_type
+      input_apk_path = "${_resource_packaged_apk_path}_${_config}"
+      _output_paths = process_file_template(
+              [ _final_apk_path ],
+              "{{source_dir}}/{{source_name_part}}-${_type}-${_config}.apk")
+      output_apk_path = _output_paths[0]
+      keystore_path = _keystore_path
+      keystore_name = _keystore_name
+      keystore_password = _keystore_password
+      deps = [
+        ":${_package_resources_target_name}",
+      ]
+    }
+  }
+
+  foreach(_split, _split_densities) {
+    _split_rule = "${target_name}__finalize_${_split}_split"
+    finalize_split(_split_rule) {
+      split_type = "density"
+      split_config = _split
+    }
+    _split_deps += [ ":$_split_rule" ]
+  }
+  foreach(_split, _split_languages) {
+    _split_rule = "${target_name}__finalize_${_split}_split"
+    finalize_split(_split_rule) {
+      split_type = "lang"
+      split_config = _split
+    }
+    _split_deps += [ ":$_split_rule" ]
+  }
 
   group(target_name) {
-    deps = [
-      ":${target_name}__finalize",
-    ]
+    public_deps = [ ":${_finalize_apk_rule_name}" ] + _split_deps
+  }
+  group("${target_name}_incremental") {
+    public_deps = [ ":${_incremental_finalize_apk_rule_name}" ] + _split_deps
   }
 }
 
 template("java_prebuilt_impl") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(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"
+
+  # Jar files can be needed at runtime (by Robolectric tests or java binaries),
+  # so do not put them under gen/.
+  _target_dir_name = get_label_info(":$target_name", "dir")
+  _jar_path = "$root_out_dir/lib.java$_target_dir_name/$target_name.jar"
+  _ijar_path =
+      "$root_out_dir/lib.java$_target_dir_name/$target_name.interface.jar"
   _build_config = _base_path + ".build_config"
 
   if (_supports_android) {
     _dex_path = _base_path + ".dex.jar"
   }
+  _deps = []
+  if (defined(invoker.deps)) {
+    _deps = invoker.deps
+  }
+  _jar_deps = []
+  if (defined(invoker.jar_dep)) {
+    _jar_deps = [ invoker.jar_dep ]
+  }
 
-  _final_deps = []
   _template_name = target_name
 
-  _final_deps += [ ":${_template_name}__build_config" ]
-  write_build_config("${_template_name}__build_config") {
+  _build_config_target_name = "${_template_name}__build_config"
+  _process_jar_target_name = "${_template_name}__process_jar"
+  _ijar_target_name = "${_template_name}__ijar"
+  if (_supports_android) {
+    _dex_target_name = "${_template_name}__dex"
+  }
+
+  write_build_config(_build_config_target_name) {
     type = "java_library"
     supports_android = _supports_android
     requires_android =
         defined(invoker.requires_android) && invoker.requires_android
 
-    deps = []
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
+    deps = _deps
     build_config = _build_config
     jar_path = _jar_path
     if (_supports_android) {
@@ -658,8 +1195,15 @@
     }
   }
 
-  _final_deps += [ ":${_template_name}__process_jar" ]
-  process_java_prebuilt("${_template_name}__process_jar") {
+  process_java_prebuilt(_process_jar_target_name) {
+    visibility = [
+      ":$_ijar_target_name",
+      ":$_template_name",
+    ]
+    if (_supports_android) {
+      visibility += [ ":$_dex_target_name" ]
+    }
+
     if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
       proguard_preprocess = true
       proguard_config = invoker.proguard_config
@@ -668,20 +1212,62 @@
     build_config = _build_config
     input_jar_path = invoker.jar_path
     output_jar_path = _jar_path
+
+    deps = [ ":$_build_config_target_name" ] + _deps + _jar_deps
+  }
+
+  generate_interface_jar(_ijar_target_name) {
+    input_jar = _jar_path
+    output_jar = _ijar_path
+    deps = [
+      ":$_process_jar_target_name",
+    ]
   }
 
   if (_supports_android) {
-    _final_deps += [ ":${_template_name}__dex" ]
-    dex("${_template_name}__dex") {
+    dex(_dex_target_name) {
       sources = [
         _jar_path,
       ]
       output = _dex_path
+      deps = [ ":$_process_jar_target_name" ] + _deps + _jar_deps
+    }
+  }
+
+  if (defined(invoker.main_class)) {
+    _binary_script_target_name = "${_template_name}__java_binary_script"
+    java_binary_script(_binary_script_target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "bootclasspath",
+                               "main_class",
+                               "wrapper_script_args",
+                             ])
+      build_config = _build_config
+      jar_path = _jar_path
+      script_name = _template_name
+      deps = [
+        ":$_build_config_target_name",
+      ]
     }
   }
 
   group(target_name) {
-    deps = _final_deps
+    forward_variables_from(invoker, [ "data_deps" ])
+    deps = [
+      ":$_ijar_target_name",
+      ":$_process_jar_target_name",
+    ]
+    if (_supports_android) {
+      deps += [ ":$_dex_target_name" ]
+    }
+    data_deps = []
+    if (defined(invoker.data_deps)) {
+      data_deps += invoker.data_deps
+    }
+    if (defined(invoker.main_class)) {
+      data_deps += [ ":$_binary_script_target_name" ]
+    }
   }
 }
 
@@ -689,7 +1275,7 @@
 #
 # Outputs:
 #  $jar_path.jar
-#  $jar_path.jar.TOC
+#  $jar_path.interface.jar
 #
 # Variables
 #   java_files: List of .java files to compile.
@@ -702,9 +1288,7 @@
 #     "${target_gen_dir}/${target_name}.jar.
 template("compile_java") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(invoker, [ "testonly" ])
 
   assert(defined(invoker.java_files))
   assert(defined(invoker.build_config))
@@ -712,7 +1296,11 @@
 
   _java_files = invoker.java_files
   _final_jar_path = invoker.jar_path
-  _intermediate_jar_path = "$target_gen_dir/$target_name.initial.jar"
+  _javac_jar_path = "$target_gen_dir/$target_name.javac.jar"
+  _process_prebuilt_jar_path =
+      "$target_gen_dir/$target_name.process_prebuilt.jar"
+  _final_ijar_path = get_path_info(_final_jar_path, "dir") + "/" +
+                     get_path_info(_final_jar_path, "name") + ".interface.jar"
 
   _build_config = invoker.build_config
 
@@ -725,6 +1313,24 @@
   if (defined(invoker.chromium_code)) {
     _chromium_code = invoker.chromium_code
   }
+
+  _supports_android = true
+  if (defined(invoker.supports_android)) {
+    _supports_android = invoker.supports_android
+  }
+
+  _enable_errorprone = use_errorprone_java_compiler
+  if (!_chromium_code) {
+    _enable_errorprone = false
+  } else if (defined(invoker.enable_errorprone)) {
+    _enable_errorprone = invoker.enable_errorprone
+  }
+
+  _enable_incremental_javac = enable_incremental_javac
+  if (defined(invoker.enable_incremental_javac)) {
+    _enable_incremental_javac = invoker.enable_incremental_javac
+  }
+
   _manifest_entries = []
   if (defined(invoker.manifest_entries)) {
     _manifest_entries = invoker.manifest_entries
@@ -748,77 +1354,137 @@
   # 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)
+  _rebased_jar_path = rebase_path(_javac_jar_path, root_build_dir)
 
-  _template_name = target_name
-  _final_deps = [ ":${_template_name}__javac" ]
-  action("${_template_name}__javac") {
+  _javac_target_name = "${target_name}__javac"
+  _process_prebuilt_target_name = "${target_name}__process_prebuilt"
+  _emma_instr_target_name = "${target_name}__emma_instr"
+  _ijar_target_name = "${target_name}__ijar"
+  _final_target_name = target_name
+
+  action(_javac_target_name) {
     script = "//build/android/gyp/javac.py"
     depfile = "$target_gen_dir/$target_name.d"
-    deps = []
+    deps = _srcjar_deps
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+
     outputs = [
       depfile,
-      _intermediate_jar_path,
-      _intermediate_jar_path + ".md5.stamp",
+      _javac_jar_path,
+      _javac_jar_path + ".md5.stamp",
     ]
     sources = _java_files + _java_srcjars
-    inputs = _system_jars + [ _build_config ]
+    inputs = [
+      _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",
+      "--use-ijars",
       "--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",
     ]
+    if (_enable_incremental_javac) {
+      args += [ "--incremental" ]
+      deps += [ "//third_party/jmake" ]
+      outputs += [ "${_javac_jar_path}.pdb" ]
+    }
+    if (_supports_android) {
+      if (defined(invoker.alternative_android_sdk_ijar)) {
+        deps += [ invoker.alternative_android_sdk_ijar_dep ]
+        _android_sdk_ijar = invoker.alternative_android_sdk_ijar
+      } else {
+        deps += [ "//build/android:android_ijar" ]
+        _android_sdk_ijar = "$root_out_dir/lib.java/android.interface.jar"
+      }
+      inputs += [ _android_sdk_ijar ]
+      _rebased_android_sdk_ijar = rebase_path(_android_sdk_ijar, root_build_dir)
+      args += [ "--bootclasspath=$_rebased_android_sdk_ijar" ]
+    }
     foreach(e, _manifest_entries) {
       args += [ "--manifest-entry=" + e ]
     }
     if (_chromium_code) {
       args += [ "--chromium-code=1" ]
     }
-
+    if (_enable_errorprone) {
+      deps += [ "//third_party/errorprone:chromium_errorprone" ]
+      args += [
+        "--use-errorprone-path",
+        "bin/chromium_errorprone",
+      ]
+    }
     args += rebase_path(_java_files, root_build_dir)
   }
 
-  _final_deps += [ ":${_template_name}__finish" ]
-  process_java_prebuilt("${_template_name}__finish") {
+  process_java_prebuilt(_process_prebuilt_target_name) {
     build_config = _build_config
-    input_jar_path = _intermediate_jar_path
-    output_jar_path = _final_jar_path
+    input_jar_path = _javac_jar_path
+    output_jar_path = _process_prebuilt_jar_path
     if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
       proguard_preprocess = invoker.proguard_preprocess
       proguard_config = invoker.proguard_config
     }
+    deps = [
+      ":$_javac_target_name",
+    ]
   }
 
-  group(target_name) {
-    deps = _final_deps
+  emma_instr(_emma_instr_target_name) {
+    visibility = [
+      ":$_ijar_target_name",
+      ":$_final_target_name",
+    ]
+
+    forward_variables_from(invoker, [ "emma_instrument" ])
+
+    input_jar_path = _process_prebuilt_jar_path
+    output_jar_path = _final_jar_path
+    source_files = _java_files
+
+    deps = [
+      ":$_process_prebuilt_target_name",
+    ]
+  }
+
+  generate_interface_jar(_ijar_target_name) {
+    input_jar = _final_jar_path
+    output_jar = _final_ijar_path
+    deps = [
+      ":$_emma_instr_target_name",
+    ]
+  }
+
+  group(_final_target_name) {
+    forward_variables_from(invoker, [ "visibility" ])
+    public_deps = [
+      ":$_emma_instr_target_name",
+      ":$_ijar_target_name",
+    ]
   }
 }
 
 template("java_library_impl") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(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"
+
+  # Jar files can be needed at runtime (by Robolectric tests or java binaries),
+  # so do not put them under gen/.
+  target_dir_name = get_label_info(":$target_name", "dir")
+  _jar_path = "$root_out_dir/lib.java$target_dir_name/$target_name.jar"
   if (defined(invoker.jar_path)) {
     _jar_path = invoker.jar_path
   }
@@ -834,6 +1500,26 @@
       defined(invoker.supports_android) && invoker.supports_android
   _requires_android =
       defined(invoker.requires_android) && invoker.requires_android
+  assert(_requires_android || true)  # Mark as used.
+  _android_manifest = "//build/android/AndroidManifest.xml"
+  if (defined(invoker.android_manifest)) {
+    _android_manifest = invoker.android_manifest
+  }
+  assert(_android_manifest != "")  # Mark as used.
+  _run_findbugs = defined(invoker.run_findbugs) && invoker.run_findbugs
+  assert(_run_findbugs || true)  # Mark as used.
+
+  _chromium_code = true
+  if (defined(invoker.chromium_code)) {
+    _chromium_code = invoker.chromium_code
+  }
+
+  _emma_never_instrument = !_chromium_code
+  if (defined(invoker.emma_never_instrument)) {
+    _emma_never_instrument = invoker.emma_never_instrument
+  }
+  assert(_emma_never_instrument || true)  # Mark as used
+  _emma_instrument = emma_coverage && !_emma_never_instrument
 
   if (_supports_android) {
     _dex_path = _base_path + ".dex.jar"
@@ -842,23 +1528,31 @@
     }
   }
 
+  # Define build_config_deps which will be a list of targets required to
+  # build the _build_config.
   if (defined(invoker.override_build_config)) {
     _build_config = invoker.override_build_config
+
+    # When a custom build config file is specified, we need to use the deps
+    # supplied by the invoker any time we reference the build config file.
+    assert(defined(invoker.deps),
+           "If you specify a build config file for " +
+               "java_library_impl($target_name), you should " +
+               "also specify the target that made it in the deps")
+    build_config_deps = invoker.deps
   } else {
     _build_config = _base_path + ".build_config"
-    _final_deps += [ ":${_template_name}__build_config" ]
-    write_build_config("${_template_name}__build_config") {
+    build_config_target_name = "${_template_name}__build_config"
+    build_config_deps = [ ":$build_config_target_name" ]
+
+    write_build_config(build_config_target_name) {
+      forward_variables_from(invoker, [ "deps" ])
       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) {
@@ -867,11 +1561,6 @@
     }
   }
 
-  _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
@@ -883,9 +1572,7 @@
   }
 
   _java_files = []
-  if (defined(invoker.java_files)) {
-    _java_files = invoker.java_files
-  } else if (defined(invoker.DEPRECATED_java_in_dir)) {
+  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) ],
@@ -894,92 +1581,87 @@
            "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_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)
   }
+  if (defined(invoker.java_files)) {
+    _java_files += invoker.java_files
+  }
   assert(_java_files != [] || _srcjar_deps != [] || _srcjars != [])
 
-  _final_deps += [ ":${_template_name}__compile_java" ]
-  compile_java("${_template_name}__compile_java") {
+  _compile_java_target = "${_template_name}__compile_java"
+  _final_deps += [ ":$_compile_java_target" ]
+  compile_java(_compile_java_target) {
+    forward_variables_from(invoker,
+                           [
+                             "alternative_android_sdk_ijar",
+                             "alternative_android_sdk_ijar_dep",
+                             "dist_jar_path",
+                             "enable_errorprone",
+                             "enable_incremental_javac",
+                             "jar_excluded_patterns",
+                             "manifest_entries",
+                             "proguard_config",
+                             "proguard_preprocess",
+                           ])
     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
-    }
+    supports_android = _supports_android
+    emma_instrument = _emma_instrument
+    deps = build_config_deps
   }
 
   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,
-      ]
+    _final_datadeps += [ ":${_template_name}__java_binary_script" ]
+    java_binary_script("${_template_name}__java_binary_script") {
+      forward_variables_from(invoker,
+                             [
+                               "bootclasspath",
+                               "main_class",
+                               "wrapper_script_args",
+                             ])
+      build_config = _build_config
+      jar_path = _jar_path
+      script_name = _template_name
+      deps = build_config_deps
     }
   }
 
   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
+        deps = [
+          ":$_compile_java_target",
+        ]
+        if (defined(invoker.deps)) {
+          deps += invoker.deps
+        }
       }
 
-      if (run_findbugs) {
+      if (_run_findbugs) {
         _final_datadeps += [ ":${_template_name}__findbugs" ]
         findbugs("${_template_name}__findbugs") {
           build_config = _build_config
           jar_path = _jar_path
+          deps = [
+            ":$_compile_java_target",
+          ]
         }
       }
     }
@@ -990,24 +1672,24 @@
         _jar_path,
       ]
       output = _dex_path
+      no_locals = _emma_instrument
+      deps = [
+        ":$_compile_java_target",
+      ]
     }
   }
 
   group(target_name) {
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
-    }
-    deps = _final_deps
-    datadeps = _final_datadeps
+    forward_variables_from(invoker, [ "visibility" ])
+    public_deps = _final_deps
+    data_deps = _final_datadeps
   }
 }
 
 # Runs process_resources.py
 template("process_resources") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(invoker, [ "testonly" ])
 
   zip_path = invoker.zip_path
   srcjar_path = invoker.srcjar_path
@@ -1022,6 +1704,11 @@
   }
 
   action(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "visibility",
+                           ])
     script = "//build/android/gyp/process_resources.py"
 
     depfile = "$target_gen_dir/$target_name.d"
@@ -1049,8 +1736,8 @@
       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),
+      "--aapt-path",
+      android_aapt_path,
       "--android-manifest",
       rebase_path(android_manifest, root_build_dir),
       "--resource-dirs=$rebase_resource_dirs",
@@ -1076,8 +1763,8 @@
       ]
     }
 
-    if (defined(invoker.v14_verify_only) && invoker.v14_verify_only) {
-      args += [ "--v14-verify-only" ]
+    if (defined(invoker.v14_skip) && invoker.v14_skip) {
+      args += [ "--v14-skip" ]
     }
 
     if (defined(invoker.shared_resources) && invoker.shared_resources) {
@@ -1098,6 +1785,14 @@
       ]
     }
 
+    if (defined(invoker.proguard_file)) {
+      outputs += [ invoker.proguard_file ]
+      args += [
+        "--proguard-file",
+        rebase_path(invoker.proguard_file, root_build_dir),
+      ]
+    }
+
     if (defined(invoker.args)) {
       args += invoker.args
     }
@@ -1106,26 +1801,18 @@
 
 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
-    }
+    sources = []
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "inputs",
+                             "sources",
+                             "testonly",
+                             "visibility",
+                           ])
+    script = "//build/android/gyp/copy_ex.py"
 
     depfile = "$target_gen_dir/$target_name.d"
     outputs = [
@@ -1148,6 +1835,17 @@
     if (defined(invoker.args)) {
       args += invoker.args
     }
+
+    if (defined(invoker.renaming_sources) &&
+        defined(invoker.renaming_destinations)) {
+      sources += invoker.renaming_sources
+      rebased_renaming_sources =
+          rebase_path(invoker.renaming_sources, root_build_dir)
+      args += [ "--renaming-sources=$rebased_renaming_sources" ]
+
+      renaming_destinations = invoker.renaming_destinations
+      args += [ "--renaming-destinations=$renaming_destinations" ]
+    }
   }
 }
 
@@ -1155,12 +1853,16 @@
 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_target_name = "${target_name}__build_config"
 
+  write_build_config(build_config_target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "dex_path",
+                           ])
+    type = "deps_dex"
     build_config = build_config
-    dex_path = invoker.dex_path
   }
 
   rebased_build_config = rebase_path(build_config, root_build_dir)
@@ -1175,6 +1877,9 @@
       excluded_jars = rebase_path(invoker.excluded_jars, root_build_dir)
       args += [ "--excluded-paths=${excluded_jars}" ]
     }
+    deps = [
+      ":$build_config_target_name",
+    ]
   }
 }
 
@@ -1185,6 +1890,11 @@
   assert(defined(invoker.split_name))
 
   action(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "testonly",
+                           ])
     depfile = "$target_gen_dir/$target_name.d"
     args = [
       "--main-manifest",
@@ -1227,3 +1937,78 @@
     ]
   }
 }
+
+# Generates a script in the output bin directory which runs the test
+# target using the test runner script in build/android/test_runner.py.
+template("test_runner_script") {
+  testonly = true
+  _test_name = invoker.test_name
+  _test_type = invoker.test_type
+
+  action(target_name) {
+    script = "//build/android/gyp/create_test_runner_script.py"
+    depfile = "$target_gen_dir/$target_name.d"
+
+    test_runner_args = [
+      _test_type,
+      "--output-directory",
+      rebase_path(root_build_dir, root_build_dir),
+    ]
+    if (_test_type == "gtest") {
+      assert(defined(invoker.test_suite))
+      test_runner_args += [
+        "--suite",
+        invoker.test_suite,
+      ]
+    } else if (_test_type == "instrumentation") {
+      deps = [
+        "${invoker.apk_target}__build_config",
+      ]
+      _build_config =
+          get_label_info(invoker.apk_target, "target_gen_dir") + "/" +
+          get_label_info(invoker.apk_target, "name") + ".build_config"
+      _rebased_build_config = rebase_path(_build_config, root_build_dir)
+      test_runner_args += [
+        "--test-apk",
+        "@FileArg($_rebased_build_config:deps_info:apk_path)",
+        "--apk-under-test",
+        "@FileArg($_rebased_build_config:deps_info:tested_apk_path)",
+      ]
+    } else {
+      assert(false, "Invalid test type: $_test_type.")
+    }
+
+    if (defined(invoker.isolate_file)) {
+      test_runner_args += [
+        "--isolate-file-path",
+        rebase_path(invoker.isolate_file, root_build_dir),
+      ]
+    }
+    if (defined(invoker.incremental_install) && invoker.incremental_install) {
+      test_runner_args += [ "--incremental-install" ]
+
+      # These can still be overridden, but make more better defaults during
+      # development.
+      test_runner_args += [
+        "--enable-device-cache",
+        "--num_retries=0",
+      ]
+    }
+    if (is_asan) {
+      test_runner_args += [ "--tool=asan" ]
+    }
+
+    generated_script = "$root_build_dir/bin/run_${_test_name}"
+    outputs = [
+      depfile,
+      generated_script,
+    ]
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--script-output-path",
+      rebase_path(generated_script, root_build_dir),
+    ]
+    args += test_runner_args
+  }
+}
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 0b7593d..a1da43a 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -5,8 +5,9 @@
 import("//base/android/linker/config.gni")
 import("//build/config/android/config.gni")
 import("//build/config/android/internal_rules.gni")
+import("//build/toolchain/toolchain.gni")
+import("//third_party/android_platform/config.gni")
 import("//tools/grit/grit_rule.gni")
-import("//tools/relocation_packer/config.gni")
 
 assert(is_android)
 
@@ -31,9 +32,7 @@
 #   }
 template("generate_jni") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(invoker, [ "testonly" ])
 
   assert(defined(invoker.sources))
   assert(defined(invoker.jni_package))
@@ -85,21 +84,15 @@
   }
 
   group(target_name) {
-    deps = [
-      ":$foreach_target_name",
-    ]
+    public_deps = []
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "public_deps",
+                             "visibility",
+                           ])
+    public_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
-    }
   }
 }
 
@@ -128,9 +121,7 @@
 #   }
 template("generate_jar_jni") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(invoker, [ "testonly" ])
 
   assert(defined(invoker.classes))
   assert(defined(invoker.jni_package))
@@ -192,13 +183,14 @@
   }
 
   group(target_name) {
-    deps = jni_actions
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
-    if (defined(invoker.public_deps)) {
-      public_deps = invoker.public_deps
-    }
+    public_deps = []
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "public_deps",
+                             "visibility",
+                           ])
+    public_deps += jni_actions
     public_configs = [ ":jni_includes_${target_name}" ]
   }
 }
@@ -240,9 +232,7 @@
 #   }
 template("java_cpp_template") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(invoker, [ "testonly" ])
 
   assert(defined(invoker.sources))
   package_name = invoker.package_name + ""
@@ -253,7 +243,18 @@
     include_path = "//"
   }
 
-  action_foreach("${target_name}__apply_gcc") {
+  apply_gcc_target_name = "${target_name}__apply_gcc"
+  zip_srcjar_target_name = "${target_name}__zip_srcjar"
+  final_target_name = target_name
+
+  action_foreach(apply_gcc_target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "public_deps",
+                             "data_deps",
+                           ])
+    visibility = [ ":$zip_srcjar_target_name" ]
     script = "//build/android/gyp/gcc_preprocess.py"
     if (defined(invoker.inputs)) {
       inputs = invoker.inputs + []
@@ -291,19 +292,24 @@
     }
   }
 
-  apply_gcc_outputs = get_target_outputs(":${target_name}__apply_gcc")
-  base_gen_dir = get_label_info(":${target_name}__apply_gcc", "target_gen_dir")
+  apply_gcc_outputs = get_target_outputs(":$apply_gcc_target_name")
+  base_gen_dir = get_label_info(":$apply_gcc_target_name", "target_gen_dir")
 
   srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
-  zip("${target_name}__zip_srcjar") {
+  zip(zip_srcjar_target_name) {
+    visibility = [ ":$final_target_name" ]
     inputs = apply_gcc_outputs
     output = srcjar_path
     base_dir = base_gen_dir
+    deps = [
+      ":$apply_gcc_target_name",
+    ]
   }
 
-  group(target_name) {
-    deps = [
-      ":${target_name}__zip_srcjar",
+  group(final_target_name) {
+    forward_variables_from(invoker, [ "visibility" ])
+    public_deps = [
+      ":$zip_srcjar_target_name",
     ]
   }
 }
@@ -321,64 +327,41 @@
 #     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") {
+  action(target_name) {
     # The sources aren't compiled so don't check their dependencies.
     check_includes = false
+    set_sources_assignment_filter([])
 
-    sources = invoker.sources
+    assert(defined(invoker.sources))
+    forward_variables_from(invoker,
+                           [
+                             "sources",
+                             "testonly",
+                             "visibility",
+                           ])
+
     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")
+    depfile = "$target_gen_dir/$target_name.d"
 
-    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)
-  }
+    _srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
+    _rebased_srcjar_path = rebase_path(_srcjar_path, root_build_dir)
+    _rebased_sources = 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",
+    args = [
+             "--depfile",
+             rebase_path(depfile, root_build_dir),
+             "--srcjar=$_rebased_srcjar_path",
+           ] + _rebased_sources
+    outputs = [
+      depfile,
+      _srcjar_path,
     ]
   }
 }
@@ -392,20 +375,20 @@
 #     processing environment, e.g. ["name=foo", "color=red"].
 #
 # Example
-#   jinja_template("chrome_shell_manifest") {
-#     input = "shell/java/AndroidManifest.xml"
+#   jinja_template("chrome_public_manifest") {
+#     input = "java/AndroidManifest.xml"
 #     output = "$target_gen_dir/AndroidManifest.xml"
 #   }
 template("jinja_template") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(invoker, [ "testonly" ])
 
   assert(defined(invoker.input))
   assert(defined(invoker.output))
 
   action(target_name) {
+    forward_variables_from(invoker, [ "visibility" ])
+
     sources = [
       invoker.input,
     ]
@@ -448,16 +431,14 @@
 #     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"]
+#   jinja_template_resources("chrome_public_template_resources") {
+#     res_dir = "res_template"
+#     resources = ["res_template/xml/syncable.xml"]
 #     variables = ["color=red"]
 #   }
 template("jinja_template_resources") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(invoker, [ "testonly" ])
 
   assert(defined(invoker.resources))
   assert(defined(invoker.res_dir))
@@ -499,13 +480,76 @@
   }
 
   group(target_name) {
-    deps = [
+    public_deps = [
       ":${target_name}__build_config",
       ":${target_name}__template",
     ]
   }
 }
 
+# Creates a resources.zip with locale.pak files placed into appropriate
+# resource configs (e.g. en-GB.pak -> res/raw-en/en_gb.pak). Also generates
+# a locale_paks TypedArray so that resource files can be enumerated at runtime.
+#
+# If this target is included in the deps of an android resources/library/apk,
+# the resources will be included with that target.
+#
+# Variables:
+#   sources: List of .pak files. Names must be of the form "en.pak" or
+#       "en-US.pak".
+#   deps: (optional) List of dependencies that might be needed to generate
+#       the .pak files.
+#
+# Example
+#   locale_pak_resources("locale_paks") {
+#     sources = [ "path/en-US.pak", "path/fr.pak", ... ]
+#   }
+template("locale_pak_resources") {
+  set_sources_assignment_filter([])
+  assert(defined(invoker.sources))
+
+  _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}__create_resources_zip") {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "sources",
+                           ])
+    script = "//build/android/gyp/locale_pak_resources.py"
+    depfile = "$target_gen_dir/$target_name.d"
+
+    outputs = [
+      depfile,
+      _resources_zip,
+    ]
+
+    _rebased_sources = rebase_path(sources, root_build_dir)
+    args = [
+      "--locale-paks=${_rebased_sources}",
+      "--resources-zip",
+      rebase_path(_resources_zip, root_build_dir),
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+    ]
+  }
+
+  group(target_name) {
+    public_deps = [
+      ":${target_name}__build_config",
+      ":${target_name}__create_resources_zip",
+    ]
+  }
+}
+
 # Declare an Android resources target
 #
 # This creates a resources zip file that will be used when building an Android
@@ -523,28 +567,29 @@
 #   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.
+#   v14_skip: If true, don't run v14 resource generator on this. Defaults to
+#     false. (see build/android/gyp/generate_v14_compatible_resources.py)
+#
 #   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
+# Example:
 #   android_resources("foo_resources") {
 #     deps = [":foo_strings_grd"]
 #     resource_dirs = ["res"]
 #     custom_package = "org.chromium.foo"
 #   }
+#
+#   android_resources("foo_resources_overrides") {
+#     deps = [":foo_resources"]
+#     resource_dirs = ["res_overrides"]
+#   }
 template("android_resources") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(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"
@@ -552,46 +597,140 @@
   r_text_path = base_path + "_R.txt"
   build_config = base_path + ".build_config"
 
-  write_build_config("${target_name}__build_config") {
+  build_config_target_name = "${target_name}__build_config"
+  process_resources_target_name = "${target_name}__process_resources"
+  final_target_name = target_name
+
+  write_build_config(build_config_target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "android_manifest",
+                             "custom_package",
+                             "deps",
+                           ])
+
+    # No package means resources override their deps.
+    if (defined(custom_package) || defined(android_manifest)) {
+      r_text = r_text_path
+    } else {
+      assert(defined(invoker.deps),
+             "Must specify deps when custom_package is omitted.")
+    }
+    visibility = [ ":$process_resources_target_name" ]
+
     type = "android_resources"
     resources_zip = zip_path
     srcjar = srcjar_path
-    r_text = r_text_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
+  }
+
+  process_resources(process_resources_target_name) {
+    visibility = [ ":$final_target_name" ]
+    deps = []
+    forward_variables_from(invoker,
+                           [
+                             "android_manifest",
+                             "custom_package",
+                             "deps",
+                             "resource_dirs",
+                             "shared_resources",
+                             "v14_skip",
+                           ])
+    deps += [ ":$build_config_target_name" ]
+
+    # Always generate R.onResourcesLoaded() method, it is required for
+    # compiling ResourceRewriter, there is no side effect because the
+    # generated R.class isn't used in final apk.
+    shared_resources = true
+    if (!defined(android_manifest)) {
+      android_manifest = "//build/android/AndroidManifest.xml"
     }
   }
 
-  android_manifest = "//build/android/AndroidManifest.xml"
-  if (defined(invoker.android_manifest)) {
-    android_manifest = invoker.android_manifest
+  group(final_target_name) {
+    forward_variables_from(invoker, [ "visibility" ])
+    public_deps = [
+      ":${target_name}__process_resources",
+    ]
   }
+}
 
-  process_resources("${target_name}__process_resources") {
-    resource_dirs = invoker.resource_dirs
-    if (defined(invoker.custom_package)) {
-      custom_package = invoker.custom_package
+# Declare an Android assets target.
+#
+# Defines a set of files to include as assets in a dependent apk.
+#
+# To include these assets in an apk, this target should be listed in
+# the apk's deps, or in the deps of a library target used by an apk.
+#
+# Variables
+#   deps: Specifies the dependencies of this target. Any Android assets
+#     listed in deps will be included by libraries/apks that depend on this
+#     target.
+#   sources: List of files to include as assets.
+#   renaming_sources: List of files to include as assets and be renamed.
+#   renaming_destinations: List of asset paths for files in renaming_sources.
+#   disable_compression: Whether to disable compression for files that are
+#     known to be compressable (default: false).
+#
+# Example:
+# android_assets("content_shell_assets") {
+#   deps = [
+#     ":generates_foo",
+#     ":other_assets",
+#     ]
+#   sources = [
+#     "//path/asset1.png",
+#     "//path/asset2.png",
+#     "$target_gen_dir/foo.dat",
+#   ]
+# }
+#
+# android_assets("overriding_content_shell_assets") {
+#   deps = [ ":content_shell_assets" ]
+#   # Override foo.dat from content_shell_assets.
+#   sources = [ "//custom/foo.dat" ]
+#   renaming_sources = [ "//path/asset2.png" ]
+#   renaming_destinations = [ "renamed/asset2.png" ]
+# }
+template("android_assets") {
+  set_sources_assignment_filter([])
+  forward_variables_from(invoker, [ "testonly" ])
+
+  _build_config = "$target_gen_dir/$target_name.build_config"
+  _build_config_target_name = "${target_name}__build_config"
+
+  write_build_config(_build_config_target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "disable_compression",
+                           ])
+    type = "android_assets"
+    build_config = _build_config
+    if (defined(invoker.sources)) {
+      asset_sources = invoker.sources
     }
-
-    if (defined(invoker.v14_verify_only)) {
-      v14_verify_only = invoker.v14_verify_only
-    }
-
-    if (defined(invoker.shared_resources)) {
-      shared_resources = invoker.shared_resources
+    if (defined(invoker.renaming_sources)) {
+      assert(defined(invoker.renaming_destinations))
+      _source_count = 0
+      foreach(_, invoker.renaming_sources) {
+        _source_count += 1
+      }
+      _dest_count = 0
+      foreach(_, invoker.renaming_destinations) {
+        _dest_count += 1
+      }
+      assert(
+          _source_count == _dest_count,
+          "android_assets() renaming_sources.length != renaming_destinations.length")
+      asset_renaming_sources = invoker.renaming_sources
+      asset_renaming_destinations = invoker.renaming_destinations
     }
   }
 
   group(target_name) {
-    deps = [
-      ":${target_name}__build_config",
-      ":${target_name}__process_resources",
+    forward_variables_from(invoker, [ "visibility" ])
+    public_deps = [
+      ":$_build_config_target_name",
     ]
   }
 }
@@ -612,19 +751,15 @@
 #  }
 template("java_strings_grd") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(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") {
+    forward_variables_from(invoker, [ "deps" ])
     type = "android_resources"
-    if (defined(invoker.deps)) {
-      deps = invoker.deps
-    }
   }
 
   # Put grit files into this subdirectory of target_gen_dir.
@@ -651,10 +786,13 @@
     base_dir = grit_output_dir
     inputs = generate_strings_outputs
     output = resources_zip
+    deps = [
+      ":$grit_target_name",
+    ]
   }
 
   group(target_name) {
-    deps = [
+    public_deps = [
       ":${target_name}__build_config",
       ":${target_name}__zip",
     ]
@@ -679,31 +817,39 @@
 #  }
 template("java_strings_grd_prebuilt") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(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") {
+  build_config_target_name = "${target_name}__build_config"
+  zip_target_name = "${target_name}__zip"
+  final_target_name = target_name
+
+  write_build_config(build_config_target_name) {
+    visibility = [ ":$zip_target_name" ]
     type = "android_resources"
-    if (defined(invoker.deps)) {
-      deps = invoker.deps
-    }
   }
 
-  zip("${target_name}__zip") {
+  zip(zip_target_name) {
+    visibility = [ ":$final_target_name" ]
+
     base_dir = invoker.grit_output_dir
     inputs = rebase_path(invoker.generated_files, ".", base_dir)
     output = resources_zip
+    deps = [
+      ":$build_config_target_name",
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
   }
 
-  group(target_name) {
-    deps = [
-      ":${target_name}__build_config",
-      ":${target_name}__zip",
+  group(final_target_name) {
+    forward_variables_from(invoker, [ "visibility" ])
+    public_deps = [
+      ":$zip_target_name",
     ]
   }
 }
@@ -716,20 +862,23 @@
 # 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.
+#   enable_errorprone: If true, enables the errorprone compiler.
+#   enable_incremental_javac: Overrides the global enable_incremental_javac.
+#   main_class: When specified, a wrapper script is created within
+#     $target_out_dir/bin to launch the binary with the given class as the
+#     entrypoint.
+#   wrapper_script_args: List of additional arguments for the wrapper script.
 #
-#   datadeps, testonly
+#   data_deps, testonly
 #
 # Example
 #   java_binary("foo") {
@@ -743,34 +892,8 @@
   # 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
-    }
-
+    forward_variables_from(invoker, "*")
+    supports_android = false
     main_class = invoker.main_class
   }
 }
@@ -801,35 +924,23 @@
   set_sources_assignment_filter([])
 
   java_binary(target_name) {
+    deps = []
+    forward_variables_from(invoker, "*")
     bypass_platform_checks = true
     main_class = "org.chromium.testing.local.JunitTestMain"
+    wrapper_script_args = [
+      "-test-jars",
+      "$target_name.jar",
+    ]
     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 = [
+    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",
+      "//third_party/robolectric:robolectric_java",
     ]
-    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
-    }
   }
 }
 
@@ -849,6 +960,9 @@
 #     ease the gyp->gn conversion and will be removed in the future.
 #
 #   chromium_code: If true, extra analysis warning/errors will be enabled.
+#   enable_errorprone: If true, enables the errorprone compiler.
+#   enable_incremental_javac: Overrides the global enable_incremental_javac.
+#
 #   jar_excluded_patterns: List of patterns of .class files to exclude from the
 #     final jar.
 #
@@ -863,7 +977,7 @@
 #     dependencies for this target. This will allow depending on an
 #     android_library target, for example.
 #
-#   datadeps, testonly
+#   data_deps, testonly
 #
 # Example
 #   java_library("foo_java") {
@@ -885,49 +999,7 @@
 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
-    }
+    forward_variables_from(invoker, "*")
   }
 }
 
@@ -937,9 +1009,13 @@
 #   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.
+#   jar_dep: Target that builds jar_path (optional).
 #   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.
 #
 # Example
 #   java_prebuilt("foo_java") {
@@ -952,19 +1028,7 @@
 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
-    }
+    forward_variables_from(invoker, "*")
   }
 }
 
@@ -988,6 +1052,9 @@
 #     ease the gyp->gn conversion and will be removed in the future.
 #
 #   chromium_code: If true, extra analysis warning/errors will be enabled.
+#   enable_errorprone: If true, enables the errorprone compiler.
+#   enable_incremental_javac: Overrides the global enable_incremental_javac.
+#
 #   jar_excluded_patterns: List of patterns of .class files to exclude from the
 #     final jar.
 #
@@ -998,6 +1065,14 @@
 #   dex_path: If set, the resulting .dex.jar file will be placed under this
 #     path.
 #
+#   alternative_android_sdk_ijar: if set, the given android_sdk_ijar file
+#     replaces the default android_sdk_ijar.
+#
+#   alternative_android_sdk_ijar_dep: the target that generates
+#      alternative_android_sdk_ijar, must be set if alternative_android_sdk_ijar
+#      is used.
+#
+#   emma_never_instrument: Disables EMMA Java code coverage for this target.
 #
 # Example
 #   android_library("foo_java") {
@@ -1020,49 +1095,13 @@
   set_sources_assignment_filter([])
   assert(!defined(invoker.jar_path),
          "android_library does not support a custom jar path")
+
+  if (defined(invoker.alternative_android_sdk_ijar)) {
+    assert(defined(invoker.alternative_android_sdk_ijar_dep))
+  }
+
   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
-    }
+    forward_variables_from(invoker, "*")
 
     supports_android = true
     requires_android = true
@@ -1089,11 +1128,12 @@
 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
-    }
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "dex_path",
+                             "excluded_jars",
+                           ])
   }
 }
 
@@ -1122,21 +1162,9 @@
 template("android_java_prebuilt") {
   set_sources_assignment_filter([])
   java_prebuilt_impl(target_name) {
-    jar_path = invoker.jar_path
+    forward_variables_from(invoker, "*")
     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
-    }
   }
 }
 
@@ -1147,7 +1175,9 @@
 #
 # Variables
 #   android_manifest: Path to AndroidManifest.xml.
-#   datadeps: List of dependencies needed at runtime. These will be built but
+#   android_manifest_dep: Target that generates AndroidManifest (if applicable)
+#   chromium_code: If true, extra analysis warning/errors will be enabled.
+#   data_deps: 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
@@ -1164,11 +1194,15 @@
 #   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.
+#   native_lib_placeholders: List of placeholder filenames to add to the apk
+#     (optional).
 #   apk_under_test: For an instrumentation test apk, this is the target of the
 #     tested apk.
 #   include_all_resources - If true include all resource IDs in all generated
 #     R.java files.
 #   testonly: Marks this target as "test-only".
+#   write_asset_list: Adds an extra file to the assets, which contains a list of
+#     all other asset files.
 #
 #   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
@@ -1194,9 +1228,7 @@
 #   }
 template("android_apk") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(invoker, [ "testonly" ])
 
   assert(defined(invoker.final_apk_path) || defined(invoker.apk_name))
   assert(defined(invoker.android_manifest))
@@ -1204,10 +1236,20 @@
   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"
+  _all_resources_zip_path = "$base_path.resources.all.zip"
+  _jar_path = "$base_path.jar"
+  _lib_dex_path = "$base_path.dex.jar"
+  _rebased_lib_dex_path = rebase_path(_lib_dex_path, root_build_dir)
   _template_name = target_name
+
+  enable_multidex = defined(invoker.enable_multidex) && invoker.enable_multidex
+  if (enable_multidex) {
+    final_dex_path = "$gen_dir/classes.dex.zip"
+  } else {
+    final_dex_path = "$gen_dir/classes.dex"
+  }
+  final_dex_target_name = "${_template_name}__final_dex"
+
   _final_apk_path = ""
   if (defined(invoker.final_apk_path)) {
     _final_apk_path = invoker.final_apk_path
@@ -1219,12 +1261,26 @@
           [ _final_apk_path ],
           "$root_build_dir/test.lib.java/{{source_name_part}}.jar")
   _dist_jar_path = _dist_jar_path_list[0]
+  _final_apk_path_no_ext_list =
+      process_file_template([ _final_apk_path ],
+                            "{{source_dir}}/{{source_name_part}}")
+  _final_apk_path_no_ext = _final_apk_path_no_ext_list[0]
+  assert(_final_apk_path_no_ext != "")  # Mark as used.
 
   _native_libs = []
 
-  _keystore_path = android_default_keystore_path
-  _keystore_name = android_default_keystore_name
-  _keystore_password = android_default_keystore_password
+  _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_path = android_keystore_path
+  _keystore_name = android_keystore_name
+  _keystore_password = android_keystore_password
 
   if (defined(invoker.keystore_path)) {
     _keystore_path = invoker.keystore_path
@@ -1237,92 +1293,123 @@
     _srcjar_deps += invoker.srcjar_deps
   }
 
-  _load_library_from_apk = false
+  _use_chromium_linker =
+      defined(invoker.use_chromium_linker) && invoker.use_chromium_linker &&
+      chromium_linker_supported
+  _enable_relocation_packing =
+      defined(invoker.enable_relocation_packing) &&
+      invoker.enable_relocation_packing && _use_chromium_linker
+  _load_library_from_apk =
+      defined(invoker.load_library_from_apk) && invoker.load_library_from_apk
 
-  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
+  assert(_use_chromium_linker || true)  # Mark as used.
+  assert(_enable_relocation_packing || true)  # Mark as used.
+
+  assert(
+      !_load_library_from_apk || _use_chromium_linker,
+      "Loading library from the apk requires use" + " of the Chromium linker.")
+
+  # The dependency that makes the chromium linker, if any is needed.
+  _native_libs_deps = []
+
+  if (defined(invoker.native_libs) && invoker.native_libs != []) {
+    if (is_component_build) {
+      _native_libs += [ "$root_shlib_dir/libc++_shared.so" ]
+      _native_libs_deps += [ "//build/android:cpplib_stripped" ]
     }
 
-    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.")
+    # Allow native_libs to be in the form "foo.so" or "foo.cr.so"
+    _first_ext_removed =
+        process_file_template(invoker.native_libs, "{{source_name_part}}")
+    _native_libs += process_file_template(
+            _first_ext_removed,
+            "$root_shlib_dir/{{source_name_part}}$shlib_extension")
+
+    _native_lib_version_rule = ""
+    if (defined(invoker.native_lib_version_rule)) {
+      _native_lib_version_rule = invoker.native_lib_version_rule
     }
-
-    _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
+    _native_lib_version_arg = "\"\""
+    if (defined(invoker.native_lib_version_arg)) {
+      _native_lib_version_arg = invoker.native_lib_version_arg
     }
   }
 
+  _android_manifest_deps = []
+  if (defined(invoker.android_manifest_dep)) {
+    _android_manifest_deps = [ invoker.android_manifest_dep ]
+  }
   _android_manifest = invoker.android_manifest
-  _rebased_build_config = rebase_path(_build_config, root_build_dir)
 
-  write_build_config("${_template_name}__build_config") {
+  _rebased_build_config = rebase_path(_build_config, root_build_dir)
+  _create_abi_split =
+      defined(invoker.create_abi_split) && invoker.create_abi_split
+  _create_density_splits =
+      defined(invoker.create_density_splits) && invoker.create_density_splits
+  _create_language_splits =
+      defined(invoker.language_splits) && invoker.language_splits != []
+
+  # Help GN understand that _create_abi_split is not unused (bug in GN).
+  assert(_create_abi_split || true)
+
+  _proguard_enabled =
+      defined(invoker.proguard_enabled) && invoker.proguard_enabled
+  if (_proguard_enabled) {
+    _proguard_jar_path = "$base_path.proguard.jar"
+  }
+
+  _emma_never_instrument = defined(invoker.testonly) && invoker.testonly
+
+  build_config_target = "${_template_name}__build_config"
+  write_build_config(build_config_target) {
+    forward_variables_from(invoker, [ "apk_under_test" ])
     type = "android_apk"
+    jar_path = _jar_path
     dex_path = final_dex_path
+    apk_path = _final_apk_path
     resources_zip = resources_zip_path
     build_config = _build_config
     android_manifest = _android_manifest
 
+    deps = _native_libs_deps + _android_manifest_deps
     if (defined(invoker.deps)) {
-      deps = invoker.deps
+      deps += invoker.deps
     }
 
-    if (defined(invoker.apk_under_test)) {
-      apk_under_test = invoker.apk_under_test
+    proguard_enabled = _proguard_enabled
+    if (_proguard_enabled) {
+      proguard_info = "$_proguard_jar_path.info"
     }
 
     native_libs = _native_libs
   }
 
-  final_deps = []
+  _final_deps = []
 
-  final_deps += [ ":${_template_name}__process_resources" ]
-  process_resources("${_template_name}__process_resources") {
+  _generated_proguard_config = "$base_path.resources.proguard.txt"
+  process_resources_target = "${_template_name}__process_resources"
+  process_resources(process_resources_target) {
+    forward_variables_from(invoker,
+                           [
+                             "include_all_resources",
+                             "shared_resources",
+                           ])
     srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
     r_text_path = "${target_gen_dir}/${target_name}_R.txt"
     android_manifest = _android_manifest
     resource_dirs = [ "//build/android/ant/empty/res" ]
     zip_path = resources_zip_path
+    all_resources_zip_path = _all_resources_zip_path
     generate_constant_ids = true
-    build_config = _build_config
+    proguard_file = _generated_proguard_config
 
-    if (defined(invoker.include_all_resources)) {
-      include_all_resources = invoker.include_all_resources
+    build_config = _build_config
+    deps = _android_manifest_deps + [ ":$build_config_target" ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
     }
   }
-  _srcjar_deps += [ ":${_template_name}__process_resources" ]
+  _srcjar_deps += [ ":$process_resources_target" ]
 
   if (_native_libs != []) {
     _enable_chromium_linker_tests = false
@@ -1338,11 +1425,17 @@
       inputs = [
         _build_config,
       ]
+      deps = [
+        ":$build_config_target",
+      ]
+      if (_native_lib_version_rule != "") {
+        deps += [ _native_lib_version_rule ]
+      }
 
       defines = [
         "NATIVE_LIBRARIES_LIST=" +
             "@FileArg($_rebased_build_config:native:java_libraries_list)",
-        "NATIVE_LIBRARIES_VERSION_NUMBER=\"$_native_lib_version_name\"",
+        "NATIVE_LIBRARIES_VERSION_NUMBER=$_native_lib_version_arg",
       ]
       if (_use_chromium_linker) {
         defines += [ "ENABLE_CHROMIUM_LINKER" ]
@@ -1357,13 +1450,20 @@
     _srcjar_deps += [ ":${_template_name}__native_libraries_java" ]
   }
 
-  final_deps += [ ":${_template_name}__java" ]
-  java_library_impl("${_template_name}__java") {
+  java_target = "${_template_name}__java"
+  java_library_impl(java_target) {
+    forward_variables_from(invoker, [ "run_findbugs" ])
     supports_android = true
     requires_android = true
     override_build_config = _build_config
+    deps = _android_manifest_deps + [ ":$build_config_target" ]
+
     android_manifest = _android_manifest
     chromium_code = true
+    if (defined(invoker.chromium_code)) {
+      chromium_code = invoker.chromium_code
+    }
+
     if (defined(invoker.java_files)) {
       java_files = invoker.java_files
     } else if (defined(invoker.DEPRECATED_java_in_dir)) {
@@ -1372,16 +1472,23 @@
       java_files = []
     }
     srcjar_deps = _srcjar_deps
-    dex_path = base_path + ".dex.jar"
+    jar_path = _jar_path
+    dex_path = _lib_dex_path
+    emma_never_instrument = _emma_never_instrument
+
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
   }
 
   if (_dist_jar_path != "") {
-    final_deps += [ ":${_template_name}__create_dist_jar" ]
+    create_dist_target = "${_template_name}__create_dist_jar"
+    _final_deps += [ ":$create_dist_target" ]
 
     # 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") {
+    action(create_dist_target) {
       script = "//build/android/gyp/create_dist_jar.py"
       depfile = "$target_gen_dir/$target_name.d"
       inputs = [
@@ -1398,120 +1505,406 @@
         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)
+      inputs += [ _jar_path ]
+      _rebased_jar_path = rebase_path([ _jar_path ], root_build_dir)
       args += [ "--inputs=$_rebased_jar_path" ]
+      deps = [
+        ":$build_config_target",  # Generates the build config file.
+        ":$java_target",  # Generates the jar file.
+      ]
     }
   }
 
-  final_deps += [ ":${_template_name}__final_dex" ]
-  dex("${_template_name}__final_dex") {
-    deps = [
-      ":${_template_name}__java",
-    ]
-    sources = [
-      jar_path,
-    ]
+  if (_proguard_enabled) {
+    _proguard_configs = [ _generated_proguard_config ]
+    if (defined(invoker.proguard_configs)) {
+      _proguard_configs += invoker.proguard_configs
+    }
+    _proguard_target = "${_template_name}__proguard"
+    proguard(_proguard_target) {
+      deps = [
+        ":$build_config_target",
+        ":$java_target",
+        ":$process_resources_target",
+      ]
+      inputs = [
+                 _build_config,
+                 _jar_path,
+               ] + _proguard_configs
+
+      output_jar_path = _proguard_jar_path
+      rebased_proguard_configs = rebase_path(_proguard_configs, root_build_dir)
+      args = [
+        "--proguard-configs=$rebased_proguard_configs",
+        "--tested-apk-info=@FileArg($_rebased_build_config:proguard:tested_apk_info)",
+        "--input-paths=@FileArg($_rebased_build_config:proguard:input_paths)",
+      ]
+    }
+    _dex_sources = [ _proguard_jar_path ]
+    _dex_deps = [ ":$_proguard_target" ]
+  } else {
+    if (enable_multidex) {
+      _dex_sources = [ _jar_path ]
+    } else {
+      _dex_sources = [ _lib_dex_path ]
+    }
+    _dex_deps = [ ":$java_target" ]
+  }
+
+  dex("$final_dex_target_name") {
+    forward_variables_from(invoker, [ "enable_multidex" ])
+    deps = _dex_deps + [ ":$build_config_target" ]
     inputs = [
       _build_config,
     ]
+    sources = _dex_sources
     output = final_dex_path
-    dex_arg_key = "${_rebased_build_config}:final_dex:dependency_dex_files"
-    args = [ "--inputs=@FileArg($dex_arg_key)" ]
+
+    # All deps are already included in _dex_sources when proguard is used.
+    if (!_proguard_enabled) {
+      if (enable_multidex) {
+        _dex_arg_key = "${_rebased_build_config}:dist_jar:dependency_jars"
+      } else {
+        _dex_arg_key = "${_rebased_build_config}:final_dex:dependency_dex_files"
+      }
+      args = [ "--inputs=@FileArg($_dex_arg_key)" ]
+    }
+
+    if (emma_coverage && !_emma_never_instrument) {
+      no_locals = true
+      sources += [ "$android_sdk_root/tools/lib/emma_device.jar" ]
+    }
   }
 
-  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"
+  _native_libs_file_arg_dep = ":$build_config_target"
+  _native_libs_file_arg = "@FileArg($_rebased_build_config:native:libraries)"
+
+  if (_native_libs != [] && _enable_relocation_packing) {
+    _prepare_native_target_name = "${_template_name}__prepare_native"
+    _native_libs_dir = "$gen_dir/packed-libs"
+    _native_libs_json = "$gen_dir/packed-libs/filelist.json"
+    _rebased_native_libs_json = rebase_path(_native_libs_json, root_build_dir)
+
+    _native_libs_file_arg_dep = ":$_prepare_native_target_name"
+    _native_libs_file_arg = "@FileArg($_rebased_native_libs_json:files)"
+
+    action(_prepare_native_target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "deps",
+                               "public_deps",
+                             ])
+      script = "//build/android/gyp/pack_relocations.py"
       depfile = "$target_gen_dir/$target_name.d"
       outputs = [
         depfile,
-      ]
-      inputs = [ _build_config ] + _native_libs
-      deps = []
-      skip_packing_list = [
-        "gdbserver",
-        "libchromium_android_linker.so",
+        _native_libs_json,
       ]
 
-      enable_packing_arg = 0
-      if (_enable_relocation_packing) {
-        enable_packing_arg = 1
-        deps += [ relocation_packer_target ]
-      }
+      inputs = _native_libs + [ _build_config ]
+
+      deps += _native_libs_deps
+      deps += [
+        ":$build_config_target",
+        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",
+        "--enable-packing=1",
         "--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),
+        rebase_path(_native_libs_dir, root_build_dir),
         "--libraries=@FileArg(${_rebased_build_config}:native:libraries)",
-        "--clear-dir",
+        "--filelistjson=$_rebased_native_libs_json",
       ]
-
-      if (is_debug) {
-        rebased_gdbserver = rebase_path([ android_gdbserver ], root_build_dir)
-        inputs += [ android_gdbserver ]
-        args += [ "--libraries=$rebased_gdbserver" ]
-      }
     }
   }
 
-  final_deps += [ ":${_template_name}__create" ]
+  _extra_native_libs = []
+  _extra_native_libs_deps = []
+  if (_native_libs != []) {
+    _extra_native_libs_even_when_incremental = []
+    _extra_native_libs_even_when_incremental_deps = []
+
+    if (is_debug) {
+      _extra_native_libs_even_when_incremental = [ android_gdbserver ]
+    }
+
+    if (_use_chromium_linker) {
+      _extra_native_libs =
+          [ "$root_shlib_dir/libchromium_android_linker$shlib_extension" ]
+      _extra_native_libs_deps +=
+          [ "//base/android/linker:chromium_android_linker" ]
+    }
+  }
+
+  _final_deps += [ ":${_template_name}__create" ]
   create_apk("${_template_name}__create") {
+    deps = []
+    forward_variables_from(invoker,
+                           [
+                             "asset_location",
+                             "deps",
+                             "extensions_to_not_compress",
+                             "language_splits",
+                             "public_deps",
+                             "shared_resources",
+                             "write_asset_list",
+                           ])
     apk_path = _final_apk_path
     android_manifest = _android_manifest
-    resources_zip = all_resources_zip_path
+    assets_build_config = _build_config
+    resources_zip = _all_resources_zip_path
     dex_path = final_dex_path
     load_library_from_apk = _load_library_from_apk
+    create_density_splits = _create_density_splits
+    emma_instrument = emma_coverage && !_emma_never_instrument
 
-    version_code = "1"
-    if (defined(invoker.version_code)) {
-      version_code = invoker.version_code
+    if (!defined(extensions_to_not_compress)) {
+      # Allow icu data, v8 snapshots, and pak files to be loaded directly from
+      # the .apk.
+      # Note: These are actually suffix matches, not necessarily extensions.
+      extensions_to_not_compress = ".dat,.bin,.pak"
     }
 
-    version_name = "Developer Build"
-    if (defined(invoker.version_name)) {
-      version_name = invoker.version_name
-    }
+    version_code = _version_code
+    version_name = _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
+    # Incremental apk does not use native libs nor final dex.
+    incremental_deps = deps + _android_manifest_deps + [
+                         ":$build_config_target",
+                         ":$process_resources_target",
+                       ]
 
-      # 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
-      }
+    # This target generates the input file _all_resources_zip_path.
+    deps += _android_manifest_deps + [
+              ":$build_config_target",
+              ":$process_resources_target",
+              ":$final_dex_target_name",
+            ]
+
+    if (_native_libs != [] && !_create_abi_split) {
+      deps += _native_libs_deps + _extra_native_libs_deps +
+              _extra_native_libs_even_when_incremental_deps +
+              [ _native_libs_file_arg_dep ]
+      native_libs_filearg = _native_libs_file_arg
+      native_libs = _extra_native_libs
+      native_libs_even_when_incremental =
+          _extra_native_libs_even_when_incremental
+
+      # Placeholders necessary for some older devices.
+      # http://crbug.com/395038
+      forward_variables_from(invoker, [ "native_lib_placeholders" ])
+    }
+  }
+
+  if (_native_libs != [] && _create_abi_split) {
+    _manifest_rule = "${_template_name}__split_manifest_abi_${android_app_abi}"
+    generate_split_manifest(_manifest_rule) {
+      main_manifest = _android_manifest
+      out_manifest =
+          "$gen_dir/split-manifests/${android_app_abi}/AndroidManifest.xml"
+      split_name = "abi_${android_app_abi}"
+      deps = _android_manifest_deps
     }
 
-    if (_native_libs != []) {
-      native_libs_dir = _native_libs_dir
-      deps += [ ":${_template_name}__prepare_native" ]
+    _apk_rule = "${_template_name}__split_apk_abi_${android_app_abi}"
+    _final_deps += [ ":$_apk_rule" ]
+
+    create_apk(_apk_rule) {
+      apk_path = "${_final_apk_path_no_ext}-abi-${android_app_abi}.apk"
+      base_path = "$gen_dir/$_apk_rule"
+
+      manifest_outputs = get_target_outputs(":${_manifest_rule}")
+      android_manifest = manifest_outputs[1]
+      load_library_from_apk = _load_library_from_apk
+
+      version_code = _version_code
+      version_name = _version_name
+
+      keystore_name = _keystore_name
+      keystore_path = _keystore_path
+      keystore_password = _keystore_password
+
+      # Placeholders necessary for some older devices.
+      # http://crbug.com/395038
+      deps = []
+      forward_variables_from(invoker,
+                             [
+                               "deps",
+                               "native_lib_placeholders",
+                               "public_deps",
+                             ])
+
+      incremental_deps = deps + _extra_native_libs_even_when_incremental_deps +
+                         [ ":$_manifest_rule" ]
+      deps = []
+      deps = incremental_deps + _native_libs_deps + _extra_native_libs_deps +
+             [ _native_libs_file_arg_dep ]
+      native_libs_filearg = _native_libs_file_arg
+      native_libs = _extra_native_libs
+      native_libs_even_when_incremental =
+          _extra_native_libs_even_when_incremental
+    }
+  }
+
+  _create_incremental_script_rule_name = "${_template_name}__incremental_script"
+  action(_create_incremental_script_rule_name) {
+    script = "//build/android/incremental_install/create_install_script.py"
+    depfile = "$target_gen_dir/$target_name.d"
+    deps = [
+      _native_libs_file_arg_dep,
+    ]
+
+    _generated_script_path =
+        "${root_out_dir}/bin/install_${_template_name}_incremental"
+    outputs = [
+      depfile,
+      _generated_script_path,
+    ]
+
+    _rebased_apk_path_no_ext =
+        rebase_path(_final_apk_path_no_ext, root_build_dir)
+    _rebased_generated_script_path =
+        rebase_path(_generated_script_path, root_build_dir)
+    _rebased_depfile = rebase_path(depfile, root_build_dir)
+    _dex_arg_key = "${_rebased_build_config}:final_dex:dependency_dex_files"
+    args = [
+      "--apk-path=${_rebased_apk_path_no_ext}_incremental.apk",
+      "--script-output-path=$_rebased_generated_script_path",
+      "--dex-file=$_rebased_lib_dex_path",
+      "--dex-file-list=@FileArg($_dex_arg_key)",
+      "--depfile=$_rebased_depfile",
+    ]
+    if (_proguard_enabled) {
+      args += [ "--show-proguard-warning" ]
+    }
+    if (defined(_native_libs_file_arg)) {
+      args += [ "--native-libs=$_native_libs_file_arg" ]
+    }
+    if (_extra_native_libs != []) {
+      # Don't pass in _extra_native_libs_even_when_incremental, since these are
+      # end up in the apk and are not side-loaded.
+      _rebased_extra_native_libs =
+          rebase_path(_extra_native_libs, root_build_dir)
+      args += [ "--native-libs=$_rebased_extra_native_libs" ]
+    }
+    if (_create_density_splits) {
+      args += [ "--split=${_rebased_apk_path_no_ext}-density-*.apk" ]
+    }
+    if (_create_language_splits) {
+      args += [ "--split=${_rebased_apk_path_no_ext}-language-*.apk" ]
     }
   }
 
   group(target_name) {
-    deps = final_deps
-    if (defined(invoker.datadeps)) {
-      datadeps = invoker.datadeps
-    }
+    forward_variables_from(invoker, [ "data_deps" ])
+    public_deps = _final_deps
+  }
+  group("${target_name}_incremental") {
+    data_deps = []
+    forward_variables_from(invoker, [ "data_deps" ])
+
+    # device/commands is used by the installer script to push files via .zip.
+    data_deps += [ "//build/android/pylib/device/commands" ] +
+                 _native_libs_deps + _extra_native_libs_deps
+
+    # Since the _incremental.apk does not include use .so nor .dex from the
+    # actual target, but instead loads them at runtime, we need to explicitly
+    # depend on them here.
+    public_deps = [
+      ":${_create_incremental_script_rule_name}",
+      ":${_template_name}__create_incremental",
+      ":${java_target}",
+    ]
+  }
+}
+
+# Declare an Android instrumentation test apk
+#
+# This target creates an Android instrumentation test apk.
+#
+# Variables
+#   android_manifest: Path to AndroidManifest.xml.
+#   data_deps: 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: The apk being tested.
+#   isolate_file: Isolate file containing the list of test data dependencies.
+#
+#   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
+#   instrumentation_test_apk("foo_test_apk") {
+#     android_manifest = "AndroidManifest.xml"
+#     apk_name = "FooTest"
+#     apk_under_test = "Foo"
+#     java_files = [
+#       "android/org/chromium/foo/FooTestCase.java",
+#       "android/org/chromium/foo/FooExampleTest.java",
+#     ]
+#     deps = [
+#       ":foo_test_support_java"
+#     ]
+#   }
+template("instrumentation_test_apk") {
+  testonly = true
+  _apk_target_name = "${target_name}__apk"
+  _test_runner_target_name = "${target_name}__test_runner_script"
+
+  test_runner_script(_test_runner_target_name) {
+    forward_variables_from(invoker, [ "isolate_file" ])
+    test_name = invoker.target_name
+    test_type = "instrumentation"
+    apk_target = ":$_apk_target_name"
+  }
+
+  android_apk(_apk_target_name) {
+    deps = []
+    data_deps = []
+    forward_variables_from(invoker, "*")
+    deps += [ "//testing/android/broker:broker_java" ]
+    data_deps += [
+      "//testing/android/driver:driver_apk",
+      "//tools/android/forwarder2",
+      "//tools/android/md5sum",
+    ]
+
+    run_findbugs =
+        defined(invoker.run_findbugs) && invoker.run_findbugs &&
+        (defined(invoker.java_files) || defined(invoker.DEPRECATED_java_in_dir))
+  }
+
+  group(target_name) {
+    public_deps = [
+      ":$_apk_target_name",
+      ":$_test_runner_target_name",
+    ]
   }
 }
 
@@ -1532,6 +1925,8 @@
 #     support executables.
 #   apk_name: The name of the produced apk. If unspecified, it uses the name
 #             of the unittests_dep target postfixed with "_apk"
+#   use_default_launcher: Whether the default activity (NativeUnitTestActivity)
+#     should be used for launching tests.
 #
 # Example
 #   unittest_apk("foo_unittests_apk") {
@@ -1539,56 +1934,54 @@
 #     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
+    set_sources_assignment_filter([])
+    data_deps = []
+    deps = []
+    forward_variables_from(invoker, "*")
+    testonly = true
+
+    assert(defined(unittests_dep), "Need unittests_dep for $target_name")
+
+    test_suite_name = get_label_info(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(apk_name)) {
+      apk_name = test_suite_name
     }
-    deps = [
+
+    if (!defined(android_manifest)) {
+      android_manifest =
+          "//testing/android/native_test/java/AndroidManifest.xml"
+    }
+
+    if (!defined(unittests_binary)) {
+      unittests_binary = "lib${test_suite_name}${shlib_extension}"
+    }
+
+    final_apk_path = "$root_build_dir/${apk_name}_apk/${apk_name}-debug.apk"
+
+    if (!defined(use_default_launcher) || use_default_launcher) {
+      java_files = [
+        "//testing/android/native_test/java/src/org/chromium/native_test/NativeBrowserTestActivity.java",
+        "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java",
+        "//testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java",
+        "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java",
+      ]
+    }
+    native_libs = [ unittests_binary ]
+    deps += [
       "//base:base_java",
       "//build/android/pylib/remote/device/dummy:remote_device_dummy_apk",
       "//testing/android/appurify_support:appurify_support_java",
+      "//testing/android/reporter:reporter_java",
     ]
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
-    datadeps = [
-      "//tools/android/md5sum",
-    ]
+    data_deps += [ "//tools/android/md5sum" ]
     if (host_os == "linux") {
-      datadeps += [ "//tools/android/forwarder2" ]
-    }
-    if (defined(invoker.datadeps)) {
-      datadeps += invoker.datadeps
+      data_deps += [ "//tools/android/forwarder2" ]
     }
   }
 }
@@ -1614,9 +2007,7 @@
 #   }
 template("android_aidl") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(invoker, [ "testonly" ])
 
   srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
   aidl_path = "${android_sdk_build_tools}/aidl"
@@ -1682,34 +2073,32 @@
 #   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.
+#   include_main_binary: Whether |binary| should be copied to |dist_dir|.
 #
 # Example
 #   create_native_executable_dist("foo_dist") {
 #     dist_dir = "$root_build_dir/foo_dist"
-#     binary = "$root_build_dir/exe.stripped/foo"
+#     binary = "$root_build_dir/foo"
+#     deps = [ ":the_thing_that_makes_foo" ]
 #   }
 template("create_native_executable_dist") {
   set_sources_assignment_filter([])
-  if (defined(invoker.testonly)) {
-    testonly = invoker.testonly
-  }
+  forward_variables_from(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',
-  #],
+  find_deps_target_name = "${template_name}__find_library_dependencies"
+  copy_target_name = "${template_name}__copy_libraries_and_exe"
 
-  stripped_libraries_dir = "$root_build_dir/lib.stripped"
-  final_deps += [ ":${template_name}__find_library_dependencies" ]
-  action("${template_name}__find_library_dependencies") {
+  action(find_deps_target_name) {
+    forward_variables_from(invoker, [ "deps" ])
+    visibility = [ ":$copy_target_name" ]
+
     script = "//build/android/gyp/write_ordered_libraries.py"
     depfile = "$target_gen_dir/$target_name.d"
     inputs = [
@@ -1726,7 +2115,7 @@
       rebase_path(depfile, root_build_dir),
       "--input-libraries=$rebased_binaries",
       "--libraries-dir",
-      rebase_path(stripped_libraries_dir, root_build_dir),
+      rebase_path(root_shlib_dir, root_build_dir),
       "--output",
       rebase_path(libraries_list, root_build_dir),
       "--readelf",
@@ -1734,24 +2123,40 @@
     ]
   }
 
-  final_deps += [ ":${template_name}__copy_libraries_and_exe" ]
-  copy_ex("${template_name}__copy_libraries_and_exe") {
+  copy_ex(copy_target_name) {
+    visibility = [ ":$template_name" ]
+
     clear_dir = true
+
     inputs = [
-      binary,
       libraries_list,
     ]
+    if (defined(invoker.include_main_binary) && invoker.include_main_binary) {
+      inputs += [ binary ]
+    }
+
     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)",
+    args = [ "--files=@FileArg($rebased_libraries_list:lib_paths)" ]
+    if (defined(invoker.include_main_binary) && invoker.include_main_binary) {
+      rebased_binaries_list = rebase_path([ binary ], root_build_dir)
+      args += [ "--files=$rebased_binaries_list" ]
+    }
+
+    deps = [
+      ":$find_deps_target_name",
     ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
   }
 
-  group(target_name) {
-    deps = final_deps
+  group(template_name) {
+    forward_variables_from(invoker, [ "visibility" ])
+    public_deps = [
+      ":$copy_target_name",
+    ]
   }
 }
 
@@ -1771,6 +2176,7 @@
 #  }
 template("proto_java_library") {
   set_sources_assignment_filter([])
+  forward_variables_from(invoker, [ "testonly" ])
   _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"
@@ -1781,9 +2187,14 @@
   action("${_template_name}__protoc_java") {
     srcjar_path = "$target_gen_dir/$target_name.srcjar"
     script = "//build/protoc_java.py"
+
     deps = [
       _protoc_dep,
     ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+
     sources = invoker.sources
     depfile = "$target_gen_dir/$target_name.d"
     outputs = [
@@ -1810,15 +2221,3 @@
     ]
   }
 }
-
-# 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
index 778ecc1..9195cfc 100644
--- a/build/config/arm.gni
+++ b/build/config/arm.gni
@@ -28,6 +28,11 @@
       arm_use_neon = false
       arm_optionally_use_neon = true
     }
+
+    if (is_ios) {
+      arm_use_neon = false
+      arm_optionally_use_neon = false
+    }
   }
 
   assert(arm_float_abi == "" || arm_float_abi == "hard" ||
@@ -53,7 +58,11 @@
     }
 
     if (arm_float_abi == "") {
-      arm_float_abi = "softfp"
+      if (is_android) {
+        arm_float_abi = "softfp"
+      } else {
+        arm_float_abi = "hard"
+      }
     }
 
     arm_use_thumb = true
diff --git a/build/config/chrome_build.gni b/build/config/chrome_build.gni
index e2ff123..de6c2c5 100644
--- a/build/config/chrome_build.gni
+++ b/build/config/chrome_build.gni
@@ -6,17 +6,22 @@
   # 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
+  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
+  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
 }
+
+# Refers to the subdirectory for branding in various places including
+# chrome/app/theme.
+if (is_chrome_branded) {
+  branding_path_component = "google_chrome"
+} else {
+  branding_path_component = "chromium"
+}
diff --git a/build/config/chromecast_build.gni b/build/config/chromecast_build.gni
new file mode 100644
index 0000000..b3d1bc2
--- /dev/null
+++ b/build/config/chromecast_build.gni
@@ -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.
+
+# This block should only contain Chromecast-specific build arguments used by
+# by components outside of //chromecast.
+declare_args() {
+  # Set this true for a Chromecast build. Chromecast builds are supported on
+  # Linux and Android.
+  is_chromecast = false
+
+  # Set this true for an audio-only Chromecast build.
+  disable_display = false
+}
+
+# Assert that Chromecast is being built for a supported platform.
+assert(is_linux || is_android || !is_chromecast,
+       "Chromecast builds are not supported on $target_os")
+
+# Assert that disable_display is not true on a non-Chromecast build.
+assert(!disable_display || is_chromecast)
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn
index e79a7b9..02c5f2c 100644
--- a/build/config/clang/BUILD.gn
+++ b/build/config/clang/BUILD.gn
@@ -31,21 +31,15 @@
       ]
     }
 
-    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",
+      "-Xclang",
+      "-plugin-arg-find-bad-constructs",
+      "-Xclang",
+      "check-templates",
     ]
   }
 }
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 0e28e7d..08d10a4 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -4,6 +4,10 @@
 
 import("//build/config/android/config.gni")
 import("//build/config/chrome_build.gni")
+import("//build/config/compiler/compiler.gni")
+import("//build/config/nacl/config.gni")
+import("//build/toolchain/ccache.gni")
+
 if (current_cpu == "arm") {
   import("//build/config/arm.gni")
 }
@@ -13,10 +17,16 @@
 if (is_posix) {
   import("//build/config/gcc/gcc_version.gni")
 }
-
-import("//build/toolchain/ccache.gni")
+if (is_win) {
+  import("//build/config/win/visual_studio_version.gni")
+}
 
 declare_args() {
+  # Default to warnings as errors for default workflow, where we catch
+  # warnings with known toolchains. Allow overriding this e.g. for Chromium
+  # builds on Linux that could use a different version of the compiler.
+  treat_warnings_as_errors = true
+
   # 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
@@ -26,6 +36,8 @@
   # 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"
+  binutils_path = rebase_path("//third_party/binutils/Linux_x64/Release/bin",
+                              root_build_dir)
 
   # 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.
@@ -38,17 +50,26 @@
   # 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).
+  # TODO(GYP): We should be using 64-bit gold for linking on both 64-bit Linux
+  # and 32-bit linux; 32-bit Gold runs out of address-space on 32-bit builds.
+  # However, something isn't quite working right on the 32-bit builds.
   use_gold = is_linux && current_cpu == "x64"
 
+  # When we are going to use gold we need to find it.
+  # This is initialized below, after use_gold might have been overridden.
+  gold_path = false
+
   # 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
+  #
+  # This is a placeholder value indicating that the code below should set
+  # the default.  This is necessary to delay the evaluation of the default
+  # value expression until after its input values such as use_gold have
+  # been set, e.g. by a toolchain_args() block.
+  use_debug_fission = "default"
 
   if (is_win) {
     # Whether the VS xtree header has been patched to disable warning 4702. If
@@ -58,6 +79,21 @@
   }
 }
 
+# Apply the default logic for these values if they were not set explicitly.
+if (gold_path == false) {
+  if (use_gold) {
+    gold_path = rebase_path("//third_party/binutils/Linux_x64/Release/bin",
+                            root_build_dir)
+  } else {
+    gold_path = ""
+  }
+}
+
+if (use_debug_fission == "default") {
+  use_debug_fission = is_debug && !is_win && use_gold &&
+                      linux_use_bundled_binutils && !use_ccache
+}
+
 # default_include_dirs ---------------------------------------------------------
 #
 # This is a separate config so that third_party code (which would not use the
@@ -70,11 +106,6 @@
   ]
 }
 
-# TODO(GYP): is_ubsan, is_ubsan_vptr
-if (!is_win) {
-  using_sanitizer = is_asan || is_lsan || is_tsan || is_msan
-}
-
 # compiler ---------------------------------------------------------------------
 #
 # Base compiler configuration.
@@ -83,25 +114,40 @@
 # where stuff should go. Put warning related stuff in the "warnings" config.
 
 config("compiler") {
+  asmflags = []
   cflags = []
   cflags_c = []
   cflags_cc = []
+  cflags_objc = []
+  cflags_objcc = []
   ldflags = []
   defines = []
+  configs = []
+
+  # System-specific flags. If your compiler flags apply to one of the
+  # categories here, add it to the associated file to keep this shared config
+  # smaller.
+  if (is_win) {
+    configs += [ "//build/config/win:compiler" ]
+  } else if (is_android) {
+    configs += [ "//build/config/android:compiler" ]
+  } else if (is_linux) {
+    configs += [ "//build/config/linux:compiler" ]
+  } else if (is_nacl) {
+    configs += [ "//build/config/nacl:compiler" ]
+  } else if (is_ios || is_mac) {
+    configs += [ "//build/config/mac:compiler" ]
+  }
+
+  # See the definitions below.
+  configs += [
+    ":compiler_cpu_abi",
+    ":compiler_codegen",
+  ]
 
   # 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 {
+  # some common GCC configuration.
+  if (!is_win) {
     # Common GCC compiler flags setup.
     # --------------------------------
     cflags += [ "-fno-strict-aliasing" ]  # See http://crbug.com/32204
@@ -117,34 +163,24 @@
     # Stack protection.
     if (is_mac) {
       cflags += [ "-fstack-protector-all" ]
-    } else if (is_linux) {
-      cflags += [
-        "-fstack-protector",
-        "--param=ssp-buffer-size=4",
-      ]
+    } else if (is_posix && !is_chromeos && !is_nacl) {
+      # TODO(phajdan.jr): Use -fstack-protector-strong when our gcc supports it.
+      cflags += [ "--param=ssp-buffer-size=4" ]
+      if (is_android && (current_cpu == "arm64" || current_cpu == "x86")) {
+        cflags += [ "-fno-stack-protector" ]
+      } else {
+        cflags += [ "-fstack-protector" ]
+      }
     }
 
     # Linker warnings.
-    if (!(is_chromeos && current_cpu == "arm") && !is_mac) {
+    if (!(is_chromeos && current_cpu == "arm") &&
+        !(is_android && use_order_profiling) && !is_mac && !is_ios) {
       # TODO(jochen): Enable this on chromeos on arm. http://crbug.com/356580
+      # TODO(lizeb,pasko): Fix link errors when linking with order_profiling=1
+      # crbug.com/485542
       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) {
@@ -169,37 +205,9 @@
                                              "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.
-    # -----------------------------------
+  # Non-Mac Posix compiler flags setup.
+  # -----------------------------------
+  if (is_posix && !(is_mac || is_ios)) {
     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.
@@ -219,6 +227,164 @@
       }
     }
 
+    defines += [ "_FILE_OFFSET_BITS=64" ]
+
+    if (!is_android) {
+      defines += [
+        "_LARGEFILE_SOURCE",
+        "_LARGEFILE64_SOURCE",
+      ]
+    }
+
+    if (!is_nacl) {
+      # 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",
+        ]
+        defines += [ "NO_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 && !use_cfi_diag) {
+      ldflags += [ "-Wl,-z,defs" ]
+    }
+  }
+
+  # Linux-specific compiler flags setup.
+  # ------------------------------------
+  if (use_gold) {
+    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",
+
+      # 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",
+    ]
+
+    if (!using_sanitizer) {
+      # TODO(brettw) common.gypi has this only for target toolset.
+      ldflags += [ "-Wl,--icf=all" ]
+    }
+
+    # 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) {
+    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 && is_clang)) {
+    # 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 && !is_nacl) {
+    # TODO(mcgrathr) - the NaCl GCC toolchain doesn't support either gnu++11
+    # or c++11; we technically don't need this toolchain any more, but there
+    # are still a few buildbots using it, so until those are turned off
+    # we need the !is_nacl clause and the (is_nacl && is_clang) clause, above.
+    cflags_cc += [ "-std=c++11" ]
+  }
+
+  if (is_mac) {
+    # Tell the compiler to use libc++'s headers and the linker to link
+    # against libc++.  The latter part normally requires OS X 10.7,
+    # but we still support running on 10.6.  How does this work?  Two
+    # parts:
+    # 1. Chromium's clang doesn't error on -mmacosx-version-min=10.6
+    #    combined with -stdlib=libc++ (it normally silently produced a
+    #    binary that doesn't run on 10.6)
+    # 2. Further down, library_dirs is set to
+    #    third_party/libc++-static, which contains a static
+    #    libc++.a library.  The linker then links against that instead
+    #    of against /usr/lib/libc++.dylib when it sees the -lc++ flag
+    #    added by the driver.
+    #
+    # In component builds, just link to the system libc++.  This has
+    # the effect of making everything depend on libc++, which means
+    # component-build binaries won't run on 10.6 (no libc++ there),
+    # but for a developer-only configuration that's ok.  (We don't
+    # want to raise the deployment target yet so that official and
+    # dev builds have the same deployment target.  This affects
+    # things like which functions are considered deprecated.)
+    cflags_cc += [ "-stdlib=libc++" ]
+    ldflags += [ "-stdlib=libc++" ]
+    if (!is_component_build && !is_asan) {
+      ldflags += [
+        "-L",
+        rebase_path("//third_party/libc++-static", root_build_dir),
+      ]
+    }
+  }
+
+  # Pass the same C/C++ flags to the objective C/C++ compiler.
+  cflags_objc += cflags_c
+  cflags_objcc += cflags_cc
+
+  # Assign any flags set for the C compiler to asmflags so that they are sent
+  # to the assembler. The Windows assembler takes different types of flags
+  # so only do so for posix platforms.
+  if (is_posix) {
+    asmflags += cflags
+    asmflags += cflags_c
+  }
+}
+
+# This provides the basic options to select the target CPU and ABI.
+# It is factored out of "compiler" so that special cases can use this
+# without using everything that "compiler" brings in.  Options that
+# tweak code generation for a particular CPU do not belong here!
+# See "compiler_codegen", below.
+config("compiler_cpu_abi") {
+  cflags = []
+  ldflags = []
+
+  if (is_posix && !(is_mac || is_ios)) {
     # 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") {
@@ -230,71 +396,122 @@
     } else if (current_cpu == "x86") {
       cflags += [ "-m32" ]
       ldflags += [ "-m32" ]
-      if (is_clang) {
+    } else if (current_cpu == "arm") {
+      if (is_clang && !is_android && !is_nacl) {
         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",
+          "-target",
+          "arm-linux-gnueabihf",
+        ]
+        ldflags += [
+          "-target",
+          "arm-linux-gnueabihf",
         ]
       }
-    } else if (current_cpu == "arm") {
-      cflags += [
-        "-march=$arm_arch",
-        "-mfloat-abi=$arm_float_abi",
-      ]
+      if (!is_nacl) {
+        cflags += [
+          "-march=$arm_arch",
+          "-mfloat-abi=$arm_float_abi",
+        ]
+        if (arm_use_thumb) {
+          cflags += [ "-mthumb" ]
+          if (is_android && !is_clang) {
+            # Clang doesn't support this option.
+            cflags += [ "-mthumb-interwork" ]
+          }
+        }
+      }
       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",
+        if (is_clang) {
+          cflags += [
+            "-target",
+            "mipsel-linux-gnu",
+            "-march=mips32r6",
           ]
+          ldflags += [
+            "-target",
+            "mipsel-linux-gnu",
+          ]
+        } else {
+          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" ]
+        if (is_clang) {
+          if (is_android) {
+            cflags += [
+              "-target",
+              "mipsel-linux-android",
+              "-march=mipsel",
+              "-mcpu=mips32r2",
+            ]
+            ldflags += [
+              "-target",
+              "mipsel-linux-android",
+            ]
+          } else {
+            cflags += [
+              "-target",
+              "mipsel-linux-gnu",
+              "-march=mipsel",
+              "-mcpu=mips32r2",
+            ]
+            ldflags += [
+              "-target",
+              "mipsel-linux-gnu",
+            ]
+          }
+        } else {
+          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 (is_clang) {
+          if (is_android) {
+            cflags += [
+              "-target",
+              "mipsel-linux-android",
+              "-march=mipsel",
+              "-mcpu=mips32",
+            ]
+            ldflags += [
+              "-target",
+              "mipsel-linux-android",
+            ]
+          } else {
+            cflags += [
+              "-target",
+              "mipsel-linux-gnu",
+              "-march=mipsel",
+              "-mcpu=mips32",
+            ]
+            ldflags += [
+              "-target",
+              "mipsel-linux-gnu",
+            ]
+          }
+        } else {
+          cflags += [
+            "-mips32",
+            "-Wa,-mips32",
+          ]
+        }
       }
 
       if (mips_dsp_rev == 1) {
@@ -318,183 +535,84 @@
         ]
         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",
-      ]
-      defines += [ "NO_UNWIND_TABLES" ]
-    } else {
-      cflags += [ "-funwind-tables" ]
+    } else if (current_cpu == "pnacl" && is_nacl_nonsfi) {
+      if (target_cpu == "x86" || target_cpu == "x64") {
+        cflags += [
+          "-arch",
+          "x86-32-nonsfi",
+          "--pnacl-bias=x86-32-nonsfi",
+          "--target=i686-unknown-nacl",
+        ]
+        ldflags += [
+          "-arch",
+          "x86-32-nonsfi",
+          "--target=i686-unknown-nacl",
+        ]
+      } else if (target_cpu == "arm") {
+        cflags += [
+          "-arch",
+          "arm-nonsfi",
+          "--pnacl-bias=arm-nonsfi",
+        ]
+        ldflags += [
+          "-arch",
+          "arm-nonsfi",
+        ]
+      }
     }
   }
 
-  # Linux/Android common flags setup.
-  # ---------------------------------
-  if (is_linux || is_android) {
-    cflags += [
-      "-fPIC",
-      "-pipe",  # Use pipes for communicating between sub-processes. Faster.
-    ]
+  asmflags = cflags
+}
 
-    ldflags += [
-      "-fPIC",
-      "-Wl,-z,noexecstack",
-      "-Wl,-z,now",
-      "-Wl,-z,relro",
-    ]
-    if (!using_sanitizer) {
-      ldflags += [ "-Wl,-z,defs" ]
-    }
-  }
+# This provides options to tweak code generation that are necessary
+# for particular Chromium code or for working around particular
+# compiler bugs (or the combination of the two).
+config("compiler_codegen") {
+  configs = []
+  cflags = []
 
-  # 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_nacl) {
+    configs += [ "//build/config/nacl:compiler_codegen" ]
+  } else if (is_posix && !is_mac && !is_ios) {
+    if (current_cpu == "x86") {
       if (is_clang) {
-        # Let clang find the ld.gold in the NDK.
-        ldflags += [ "--gcc-toolchain=" +
-                     rebase_path(android_toolchain_root, root_build_dir) ]
+        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") {
+      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",
 
-    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" ]
+          # The following option is disabled to improve binary
+          # size and performance in gcc 4.9.
+          "-fno-caller-saves",
+        ]
       }
     }
   }
+
+  asmflags = cflags
 }
 
 config("compiler_arm_fpu") {
-  if (current_cpu == "arm") {
+  if (current_cpu == "arm" && !is_ios && !is_nacl) {
     cflags = [ "-mfpu=$arm_fpu" ]
+    asmflags = cflags
   }
 }
 
@@ -509,220 +627,54 @@
 # target wants the option regardless, put it in the compiler config.
 
 config("runtime_library") {
-  cflags = []
   defines = []
-  ldflags = []
-  lib_dirs = []
-  libs = []
+  configs = []
+
+  # System-specific flags. If your compiler flags apply to one of the
+  # categories here, add it to the associated file to keep this shared config
+  # smaller.
+  if (is_win) {
+    configs += [ "//build/config/win:runtime_library" ]
+  } else if (is_linux) {
+    configs += [ "//build/config/linux:runtime_library" ]
+  } else if (is_ios) {
+    configs += [ "//build/config/ios:runtime_library" ]
+  } else if (is_mac) {
+    configs += [ "//build/config/mac:runtime_library" ]
+  } else if (is_android) {
+    configs += [ "//build/config/android:runtime_library" ]
+  }
+
+  if (is_posix) {
+    configs += [ "//build/config/posix:runtime_library" ]
+  }
 
   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 ---------------------------------------------------------------
+# default_warnings ------------------------------------------------------------
 #
-# 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",
-    ]
-
-    if (using_sanitizer) {
-      # _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.
-      #
-      # 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" ]
-    }
-  }
-}
-config("no_chromium_code") {
+# Collects all warning flags that are used by default.  This is used as a
+# subconfig of both chromium_code and no_chromium_code.  This way these
+# flags are guaranteed to appear on the compile command line after -Wall.
+config("default_warnings") {
   cflags = []
   cflags_cc = []
-  defines = []
 
   if (is_win) {
+    if (treat_warnings_as_errors) {
+      cflags += [ "/WX" ]
+    }
+
     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.
+      # C4091: 'typedef ': ignored on left of 'X' when no variable is
+      #                    declared.
+      # This happens in a number of Windows headers. Dumb.
+      "/wd4091",
 
       # C4127: conditional expression is constant
       # This warning can in theory catch dead code and other problems, but
@@ -762,6 +714,12 @@
       # prevent it.
       "/wd4503",
 
+      # Warning C4589 says: "Constructor of abstract class ignores
+      # initializer for virtual base class." Disable this warning because it
+      # is flaky in VS 2015 RTM. It triggers on compiler generated
+      # copy-constructors in some cases.
+      "/wd4589",
+
       # C4611: interaction between 'function' and C++ object destruction is
       #        non-portable
       # This warning is unavoidable when using e.g. setjmp/longjmp.  MSDN
@@ -782,7 +740,17 @@
       "/wd4510",  # Default constructor could not be generated.
       "/wd4512",  # Assignment operator could not be generated.
       "/wd4610",  # Class can never be instantiated, constructor required.
+      "/wd4838",  # Narrowing conversion. Doesn't seem to be very useful.
+      "/wd4995",  # 'X': name was marked as #pragma deprecated
       "/wd4996",  # Deprecated function warning.
+
+      # 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.
+      "/wd4456",
+      "/wd4457",
+      "/wd4458",
+      "/wd4459",
     ]
 
     # VS xtree header file needs to be patched or 4702 (unreachable code
@@ -792,73 +760,59 @@
         exec_script("../../win_is_xtree_patched.py", [], "value") == 0) {
       cflags += [ "/wd4702" ]  # Unreachable code.
     }
+
+    # Building with Clang on Windows is a work in progress and very
+    # experimental. See crbug.com/82385.
+    # Keep this in sync with the similar block in build/common.gypi
+    if (is_clang) {
+      cflags += [
+        # TODO(hans): Make this list shorter eventually, http://crbug.com/504657
+        "-Qunused-arguments",  # http://crbug.com/504658
+        "-Wno-microsoft-enum-value",  # http://crbug.com/505296
+        "-Wno-unknown-pragmas",  # http://crbug.com/505314
+        "-Wno-microsoft-cast",  # http://crbug.com/550065
+
+        # Disable unused-value (crbug.com/505318) except -Wunused-result.
+        "-Wno-unused-value",
+        "-Wunused-result",
+      ]
+    }
   } else {
     # Common GCC warning setup.
-    cflags = [
+    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 (treat_warnings_as_errors) {
+      cflags += [ "-Werror" ]
+    }
 
     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",
-        ]
+        # When compiling Objective-C, warns if a method is used whose
+        # availability is newer than the deployment target. This is not
+        # required when compiling Chrome for iOS.
+        cflags += [ "-Wpartial-availability" ]
       }
     }
+
     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",
       ]
+      if (!is_clang) {
+        cflags_cc += [
+          # TODO(thakis): Remove, http://crbug.com/263960
+          "-Wno-literal-suffix",
+        ]
+      }
     }
 
     # Suppress warnings about ABI changes on ARM (Clang doesn't give this
@@ -867,28 +821,6 @@
       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.
@@ -896,13 +828,185 @@
       cflags += [ "-Wno-unused-local-typedefs" ]
     }
   }
+
+  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",
+
+      # 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(hans): Get this cleaned up, http://crbug.com/428099
+      "-Wno-inconsistent-missing-override",
+    ]
+
+    if (is_posix && !is_mac && !is_ios) {
+      cflags += [
+        # 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 (Clang 3.7) does not recognize.
+      cflags += [
+        # TODO(thakis): Enable this, crbug.com/507717
+        "-Wno-shift-negative-value",
+
+        # TODO(thakis): Consider enabling this?
+        "-Wno-bitfield-width",
+      ]
+    }
+
+    if (is_nacl_nonsfi) {
+      cflags += [
+        # TODO(phosek): Enable after https://codereview.chromium.org/1419373002/
+        # is rolled into Chrome.
+        "-Wno-sign-compare",
+      ]
+    }
+  }
 }
 
+# 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",
+    ]
+
+    if (!is_debug && !using_sanitizer &&
+        (!is_linux || !is_clang || is_official_build)) {
+      # _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.
+      #
+      # 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" ]
+    }
+  }
+
+  configs = [ ":default_warnings" ]
+}
+
+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_clang) {
+    cflags += [
+      # Lots of third-party libraries have unused variables. Instead of
+      # suppressing them individually, we just blanket suppress them here.
+      "-Wno-unused-variable",
+    ]
+  }
+
+  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",
+    ]
+  }
+
+  configs = [ ":default_warnings" ]
+}
+
+# rtti ------------------------------------------------------------------------
+#
+# Allows turning Run-Time Type Identification on or off.
+
+config("rtti") {
+  if (is_win) {
+    cflags_cc = [ "/GR" ]
+  }
+}
+config("no_rtti") {
+  # CFI diagnostics and UBsan vptr require RTTI.
+  if (!use_cfi_diag && !is_ubsan_vptr) {
+    if (is_win) {
+      cflags_cc = [ "/GR-" ]
+    } else {
+      cflags_cc = [ "-fno-rtti" ]
+      cflags_objcc = cflags_cc
+    }
+  }
+}
+
+# Warnings ---------------------------------------------------------------------
+
 # 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) {
+  # TODO: Enable on Windows too, http://crbug.com/404525
+  if (is_clang && !is_win) {
     cflags = [ "-Wexit-time-destructors" ]
   }
 }
@@ -923,24 +1027,42 @@
   }
 }
 
+# Some code presumes that pointers to structures/objects are compatible
+# regardless of whether what they point to is already known to be valid.
+# gcc 4.9 and earlier had no way of suppressing this warning without
+# supressing the rest of them.  Here we centralize the identification of
+# the gcc 4.9 toolchains.
+config("no_incompatible_pointer_warnings") {
+  cflags = []
+  if (is_clang) {
+    cflags += [ "-Wno-incompatible-pointer-types" ]
+  } else if (current_cpu == "mipsel") {
+    cflags += [ "-w" ]
+  } else if (is_chromeos && current_cpu == "arm") {
+    cflags += [ "-w" ]
+  }
+}
+
 # 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:
+# The BUILDCONFIG file sets the "default_optimization" config on targets by
+# default. It will be equivalent to either "optimize" (release) or
+# "no_optimize" (debug) optimization configs.
 #
-#   configs -= default_optimization_config
-#   configs += [ "//build/config/compiler/optimize_max" ]
+# You can override the optimization level on a per-target basis by removing the
+# default config and then adding the named one you want:
+#
+#   configs -= [ "//build/config/compiler:default_optimization" ]
+#   configs += [ "//build/config/compiler:optimize_max" ]
 
 # Shared settings for both "optimize" and "optimize_max" configs.
+# IMPORTANT: On Windows "/O1" and "/O2" must go before the common flags.
 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.
+    "/Ob2",  # Both explicit and auto inlining.
+    "/Oy-",  # Disable omitting frame pointers, must be after /O2.
+    "/d2Zi+",  # Improve debugging of optimized code.
+    "/Zc:inline",  # Remove unreferenced COMDAT (faster links).
   ]
   if (!is_asan) {
     common_optimize_on_cflags += [
@@ -952,7 +1074,17 @@
       "/Gw",
     ]
   }
-  common_optimize_on_ldflags = [ "/OPT:REF" ]
+  common_optimize_on_ldflags = [ "/OPT:ICF" ]
+  if (is_official_build) {
+    common_optimize_on_ldflags += [
+      # Link-time code generation.
+      "/LTCG",
+
+      # Set the number of LTCG code-gen threads to eight. The default is four.
+      # This gives a 5-10% link speedup.
+      "/cgthreads:8",
+    ]
+  }
 } else {
   common_optimize_on_cflags = [
     # Don't emit the GCC version ident directives, they just end up in the
@@ -981,7 +1113,7 @@
     }
   }
 
-  if (is_mac) {
+  if (is_mac || is_ios) {
     if (symbol_level == 2) {
       # Mac dead code stripping requires symbols.
       common_optimize_on_ldflags += [ "-Wl,-dead_strip" ]
@@ -1004,17 +1136,22 @@
   }
 }
 
-# Default "optimization on" config. On Windows, this favors size over speed.
+# Default "optimization on" config.
 config("optimize") {
-  cflags = common_optimize_on_cflags
-  ldflags = common_optimize_on_ldflags
   if (is_win) {
-    cflags += [ "/Os" ]  # favor size over speed.
+    # Favor size over speed, /O1 must be before the common flags. The GYP
+    # build also specifies /Os and /GF but these are implied by /O1.
+    cflags = [ "/O1" ] + common_optimize_on_cflags + [ "/Oi" ]
   } else if (is_android || is_ios) {
-    cflags += [ "-Os" ]  # Favor size over speed.
+    # Favor size over speed.
+    cflags = [ "-Os" ] + common_optimize_on_cflags
   } else {
-    cflags += [ "-O2" ]
+    # Linux & Mac favor speed over size.
+    # TODO(brettw) it's weird that Mac and desktop Linux are different. We should
+    # explore favoring size over speed in this case as well.
+    cflags = [ "-O2" ] + common_optimize_on_cflags
   }
+  ldflags = common_optimize_on_ldflags
 }
 
 # Turn off optimizations.
@@ -1039,6 +1176,7 @@
     ldflags = common_optimize_on_ldflags
   } else {
     cflags = [ "-O0" ]
+    ldflags = []
   }
 }
 
@@ -1046,33 +1184,68 @@
 # 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" ]
-    }
+  if (is_nacl_irt) {
+    # The NaCl IRT is a special case and always wants its own config.
+    # Various components do:
+    #   if (!is_debug) {
+    #     configs -= [ "//build/config/compiler:default_optimization" ]
+    #     configs += [ "//build/config/compiler:optimize_max" ]
+    #   }
+    # So this config has to have the selection logic just like
+    # "default_optimization", below.
+    configs = [ "//build/config/nacl:irt_optimize" ]
   } else {
-    cflags += [ "-O2" ]
+    ldflags = common_optimize_on_ldflags
+    if (is_win) {
+      # Favor speed over size, /O2 must be before the common flags. The GYP
+      # build also specifies /Ot, /Oi, and /GF, but these are implied by /O2.
+      cflags = [ "/O2" ] + common_optimize_on_cflags
+      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",
+        ]
+      }
+    } else {
+      cflags = [ "-O2" ] + common_optimize_on_cflags
+    }
+  }
+}
+
+# The default optimization applied to all targets. This will be equivalent to
+# either "optimize" or "no_optimize", depending on the build flags.
+config("default_optimization") {
+  if (is_nacl_irt) {
+    # The NaCl IRT is a special case and always wants its own config.
+    # It gets optimized the same way regardless of the type of build.
+    configs = [ "//build/config/nacl:irt_optimize" ]
+  } else if (is_debug) {
+    configs = [ ":no_optimize" ]
+  } else {
+    configs = [ ":optimize" ]
   }
 }
 
 # Symbols ----------------------------------------------------------------------
 
+# The BUILDCONFIG file sets the "default_symbols" config on targets by
+# default. It will be equivalent to one the three specific symbol levels.
+#
+# You can override the symbol level on a per-target basis by removing the
+# default config and then adding the named one you want:
+#
+#   configs -= [ "//build/config/compiler:default_symbols" ]
+#   configs += [ "//build/config/compiler:symbols" ]
+
+# Full symbols.
 config("symbols") {
   if (is_win) {
     import("//build/toolchain/goma.gni")
@@ -1081,29 +1254,64 @@
     } else {
       cflags = [ "/Zi" ]  # Produce PDB file, no edit and continue.
     }
-    ldflags = [ "/DEBUG" ]
+    if (is_win_fastlink) {
+      # Tell VS 2015+ to create a PDB that references debug
+      # information in .obj and .lib files instead of copying
+      # it all. This flag is incompatible with /PROFILE
+      ldflags = [ "/DEBUG:FASTLINK" ]
+    } else {
+      ldflags = [ "/DEBUG" ]
+    }
   } else {
     cflags = [ "-g2" ]
     if (use_debug_fission) {
       cflags += [ "-gsplit-dwarf" ]
     }
+    asmflags = cflags
+    ldflags = []
   }
 }
 
+# Minimal symbols.
 config("minimal_symbols") {
   if (is_win) {
     # Linker symbols for backtraces only.
-    ldflags = [ "/DEBUG" ]
+    cflags = []
+    if (is_win_fastlink) {
+      # Tell VS 2015+ to create a PDB that references debug
+      # information in .obj and .lib files instead of copying
+      # it all. This flag is incompatible with /PROFILE
+      ldflags = [ "/DEBUG:FASTLINK" ]
+    } else {
+      ldflags = [ "/DEBUG" ]
+    }
   } else {
     cflags = [ "-g1" ]
     if (use_debug_fission) {
       cflags += [ "-gsplit-dwarf" ]
     }
+    asmflags = cflags
+    ldflags = []
   }
 }
 
+# No symbols.
 config("no_symbols") {
   if (!is_win) {
     cflags = [ "-g0" ]
+    asmflags = cflags
+  }
+}
+
+# Default symbols.
+config("default_symbols") {
+  if (symbol_level == 0) {
+    configs = [ ":no_symbols" ]
+  } else if (symbol_level == 1) {
+    configs = [ ":minimal_symbols" ]
+  } else if (symbol_level == 2) {
+    configs = [ ":symbols" ]
+  } else {
+    assert(false)
   }
 }
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
new file mode 100644
index 0000000..5adc470
--- /dev/null
+++ b/build/config/compiler/compiler.gni
@@ -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.
+
+import("//build/config/chrome_build.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+
+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 according to debug/release and platform.
+  symbol_level = -1
+}
+
+# If it wasn't manually set, set to an appropriate default.
+assert(symbol_level >= -1 && symbol_level <= 2, "Invalid symbol_level")
+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,
+  # but keep them on for Official builds.
+  if (!is_linux || (is_debug || is_official_build)) {
+    symbol_level = 2
+  } else if (using_sanitizer) {
+    # Sanitizers require symbols for filename suppressions to work.
+    symbol_level = 1
+  } else {
+    symbol_level = 0
+  }
+}
diff --git a/build/config/crypto.gni b/build/config/crypto.gni
index 7f090b7..99ce428 100644
--- a/build/config/crypto.gni
+++ b/build/config/crypto.gni
@@ -6,19 +6,23 @@
 #
 # TODO(brettw) this should probably be moved to src/crypto or somewhere, and
 # the global build dependency on it should be removed.
+#
+# PLEASE TRY TO AVOID ADDING FLAGS TO THIS FILE in cases where grit isn't
+# required. See the declare_args block of BUILDCONFIG.gn for advice on how
+# to set up feature flags.
 
 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
+  # Use OpenSSL instead of NSS. This is used for all platforms but iOS. (See
+  # http://crbug.com/338886).
+  use_openssl = !is_ios
 }
 
 # 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
+# verification. On NaCl, verification isn't supported. On other targets, this
+# flag also enables OpenSSL for certificate verification, but this configuration
+# is unsupported.
+use_openssl_certs = is_android || is_nacl
 
 # 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
diff --git a/build/config/features.gni b/build/config/features.gni
index 82b7d06..7a8e964 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -2,16 +2,21 @@
 # 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.
+# This file contains Chrome-feature-related build flags (see ui.gni for
+# UI-related ones). These should theoretically be moved to the build files of
+# the features themselves.
 #
 # However, today we have many "bad" dependencies on some of these flags from,
-# e.g. base, so they need to be global.
+# e.g. base, so they need to be global to match the GYP configuration. Also,
+# anything that needs a grit define must be in either this file or ui.gni.
 #
-# See also build/config/ui.gni
+# PLEASE TRY TO AVOID ADDING FLAGS TO THIS FILE in cases where grit isn't
+# required. See the declare_args block of BUILDCONFIG.gn for advice on how
+# to set up feature flags.
 
 import("//build/config/chrome_build.gni")
+import("//build/config/chromecast_build.gni")
+import("//build/config/headless_build.gni")
 if (is_android) {
   import("//build/config/android/config.gni")
 }
@@ -20,7 +25,9 @@
   # Multicast DNS.
   enable_mdns = is_win || is_linux
 
-  enable_plugins = !is_android && !is_ios
+  enable_extensions = !is_android && !is_ios
+  enable_plugins = (!is_android && !is_ios) || is_chromecast
+  enable_pdf = !is_android && !is_ios && !is_chromecast
 
   # Enables Native Client support.
   # TODO(GYP): Get NaCl linking on other platforms.
@@ -32,8 +39,9 @@
   # 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 = !is_ios && !is_android && !is_chromecast
+  enable_nacl = (is_linux || is_mac || is_nacl) && current_cpu != "mipsel" &&
+                !is_chromecast
   enable_nacl_untrusted = enable_nacl
   enable_pnacl = enable_nacl_untrusted
 
@@ -44,20 +52,19 @@
   debug_devtools = false
 
   # Enables WebRTC.
-  # TODO(GYP) make mac and android work.
-  enable_webrtc = !is_ios && !is_mac && !is_android
+  # TODO(GYP) make mac work.
+  enable_webrtc = !is_ios && !is_mac
 
   # Enables the Media Router.
-  enable_media_router = !is_ios && !is_android
+  enable_media_router = !is_ios
 
   # Enables proprietary codecs and demuxers; e.g. H264, MOV, AAC, and MP3.
   # Android OS includes support for proprietary codecs regardless of building
   # Chromium or Google Chrome. We also ship Google Chrome and Chromecast with
   # proprietary codecs.
-  # TODO(GYP) The GYP build has || chromecast==1 for this:
-  proprietary_codecs = is_android || is_chrome_branded
+  proprietary_codecs = is_android || is_chrome_branded || is_chromecast
 
-  enable_configuration_policy = true
+  enable_configuration_policy = !is_ios
 
   # Enables support for background apps.
   enable_background = !is_ios && !is_android
@@ -76,25 +83,25 @@
 
   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_remoting = !is_ios && !is_chromecast && !is_headless
 
   # 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
+  enable_browser_cdms = is_android || is_chromecast
 
-  # Variable safe_browsing is used to control the build time configuration
-  # for safe browsing feature. Safe browsing can be compiled in 4 different
-  # levels: 0 disables it, 1 enables it fully, and 2 enables only UI and
-  # reporting features for use with Data Saver on Mobile, and 3 enables
-  # extended mobile protection via an external API.  When 3 is fully deployed,
-  # it will replace 2.
+  # Hangout services is an extension that adds extra features to Hangouts.
+  # For official GYP builds, this flag is set.
+  enable_hangout_services_extension = false
+
+  # 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 mobile protection via an
+  # external API.
   if (is_android) {
     safe_browsing_mode = 2
   } else if (is_ios) {
@@ -102,34 +109,42 @@
   } else {
     safe_browsing_mode = 1
   }
+
+  # Set to true make a build that disables activation of field trial tests
+  # specified in testing/variations/fieldtrial_testing_config_*.json.
+  # Note: this setting is ignored if is_chrome_branded.
+  fieldtrial_testing_like_official_build = is_chrome_branded
+
+  use_cups = (is_desktop_linux || is_mac) && !is_chromecast && !is_headless
 }
 
 # 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.
+#   1: (DEPRECATED! See http://crbug.com/528305 for info) Use only CLD1.
 #   2: Use only CLD2.
-if (is_android) {
-  cld_version = 1
-} else {
-  cld_version = 2
-}
+cld_version = 2
 
 # libudev usage. This currently only affects the content layer.
-use_udev = is_linux
+use_udev = is_linux && !is_chromecast && !is_headless
 
 # Enable the spell checker.
-enable_spellcheck = !is_android
+enable_spellcheck = !is_ios
 
-enable_pepper_cdms = enable_plugins && (is_linux || is_mac || is_win)
+# Use the operating system's spellchecker rather than hunspell.
+use_browser_spellchecker = is_android || is_mac
 
 # Enable basic printing support and UI.
-enable_basic_printing = !is_chromeos
+enable_basic_printing =
+    !is_chromeos && !is_chromecast && !is_ios && !is_headless
 
 # 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
+enable_print_preview = !is_android && !is_chromecast && !is_ios && !is_headless
+
+# Enables the use of CDMs in pepper plugins.
+enable_pepper_cdms =
+    enable_plugins && (is_linux || is_mac || is_win) && !is_chromecast
 
 # The seccomp-bpf sandbox is only supported on three architectures
 # currently.
@@ -142,19 +157,12 @@
 # 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
+use_dbus = is_linux && !is_chromecast && !is_headless
 
 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.
@@ -162,14 +170,13 @@
 
 # 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_rlz_support = is_win || is_mac || is_ios || is_chromeos
+enable_rlz = is_chrome_branded && enable_rlz_support
 
 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
 
@@ -180,17 +187,12 @@
 # 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
+use_gconf = is_linux && !is_chromeos && !is_chromecast && !is_headless
 
-# 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
+# Enable WebVR support by default on Android
+# Still requires command line flag to access API
+enable_webvr = is_android
 
-# Whether to back up data before sync.
-enable_pre_sync_backup = is_win || is_mac || (is_linux && !is_chromeos)
+use_gio = is_desktop_linux && !is_headless
diff --git a/build/config/gcc/BUILD.gn b/build/config/gcc/BUILD.gn
index 40243cd..b6ab1d4 100644
--- a/build/config/gcc/BUILD.gn
+++ b/build/config/gcc/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/toolchain/toolchain.gni")
+
 # 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
@@ -26,11 +28,15 @@
       "-Wl,-z,nocopyreloc",
     ]
   } else {
-    # Android doesn't support rpath.
+    # Note: Android doesn't support rpath.
+    rpath_link = ""
+    if (shlib_subdir != ".") {
+      rpath_link = "${shlib_subdir}/"
+    }
     ldflags = [
       # Want to pass "\$". GN will re-escape as required for ninja.
-      "-Wl,-rpath=\$ORIGIN/",
-      "-Wl,-rpath-link=",
+      "-Wl,-rpath=\$ORIGIN/${rpath_link}",
+      "-Wl,-rpath-link=${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.
@@ -41,4 +47,5 @@
 
 config("no_exceptions") {
   cflags_cc = [ "-fno-exceptions" ]
+  cflags_objcc = cflags_cc
 }
diff --git a/build/config/gcc/gcc_version.gni b/build/config/gcc/gcc_version.gni
index 6741e45..eed1bc8 100644
--- a/build/config/gcc/gcc_version.gni
+++ b/build/config/gcc/gcc_version.gni
@@ -2,25 +2,33 @@
 # 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
+declare_args() {
+  # This allows the gcc_version to be overriden when using a custom toolchain.
+  # If the gcc_version is {X}.{Y}, set this value as XY.
+  gcc_version = -1
+}
+
+if (gcc_version == -1) {
+  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/headless_build.gni b/build/config/headless_build.gni
new file mode 100644
index 0000000..1788b25
--- /dev/null
+++ b/build/config/headless_build.gni
@@ -0,0 +1,8 @@
+# Copyright 2015 The Chromium 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() {
+  # Configure the build for headless mode. See crbug.com/546953.
+  is_headless = false
+}
diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn
index 471f28a..3b9f846 100644
--- a/build/config/ios/BUILD.gn
+++ b/build/config/ios/BUILD.gn
@@ -5,18 +5,25 @@
 import("//build/config/sysroot.gni")
 import("//build/config/ios/ios_sdk.gni")
 
-config("sdk") {
+# This is included by reference in the //build/config/compiler:runtime_library
+# config that is applied to all targets. It is here to separate out the logic
+# that is iOS-only. Please see that target for advice on what should go in
+# :runtime_library vs. :compiler.
+config("runtime_library") {
   common_flags = [
     "-isysroot",
     sysroot,
+
+    "-stdlib=libc++",
   ]
 
+  if (use_ios_simulator) {
+    common_flags += [ "-mios-simulator-version-min=$ios_deployment_target" ]
+  } else {
+    common_flags += [ "-miphoneos-version-min=$ios_deployment_target" ]
+  }
+
+  asmflags = common_flags
   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/find_signing_identity.py b/build/config/ios/find_signing_identity.py
new file mode 100644
index 0000000..9c3d493
--- /dev/null
+++ b/build/config/ios/find_signing_identity.py
@@ -0,0 +1,35 @@
+# 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.
+
+import subprocess
+import sys
+import re
+
+def ListIdentities():
+  return subprocess.check_output([
+    '/usr/bin/env',
+    'xcrun',
+    'security',
+    'find-identity',
+    '-v',
+    '-p',
+    'codesigning',
+  ]).strip()
+
+
+def FindValidIdentity():
+  lines = ListIdentities().splitlines()
+  # Look for something like "2) XYZ "iPhone Developer: Name (ABC)""
+  exp = re.compile('[0-9]+\) ([A-F0-9]+) "([^"]*)"')
+  for line in lines:
+    res = exp.match(line)
+    if res is None:
+      continue
+    if "iPhone Developer" in res.group(2):
+      return res.group(1)
+  return ""
+
+
+if __name__ == '__main__':
+  print FindValidIdentity()
diff --git a/build/config/ios/ios_app.py b/build/config/ios/ios_app.py
new file mode 100644
index 0000000..54a68ac
--- /dev/null
+++ b/build/config/ios/ios_app.py
@@ -0,0 +1,99 @@
+# 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.
+
+import argparse
+import errno
+import os
+import subprocess
+import sys
+
+
+def ProcessInfoPlist(args):
+  output_plist_file = os.path.abspath(os.path.join(args.output, 'Info.plist'))
+  return subprocess.check_call( [
+    '/usr/bin/env',
+    'xcrun',
+    'plutil',
+    '-convert',
+    'binary1',
+    '-o',
+    output_plist_file,
+    '--',
+    args.input,
+  ])
+
+
+def PerformCodeSigning(args):
+  return subprocess.check_call([
+    '/usr/bin/env',
+    'xcrun',
+    'codesign',
+    '--entitlements',
+    args.entitlements_path,
+    '--sign',
+    args.identity,
+    '-f',
+    args.application_path,
+  ])
+
+
+def MakeDirectories(path):
+  try:
+    os.makedirs(path)
+  except OSError as exc:
+    if exc.errno == errno.EEXIST and os.path.isdir(path):
+      return 0
+    else:
+      return -1
+  return 0
+
+
+def GenerateProjectStructure(args):
+  application_path = os.path.join(args.dir, args.name + ".app")
+  return MakeDirectories( application_path )
+
+
+def main():
+  parser = argparse.ArgumentParser(description='A script that aids in '
+                                   'the creation of an iOS application')
+  subparsers = parser.add_subparsers()
+
+  # Plist Parser
+  plist_parser = subparsers.add_parser('plist',
+                                       help='Process the Info.plist')
+  plist_parser.set_defaults(func=ProcessInfoPlist)
+
+  plist_parser.add_argument('-i', dest='input', help='The input plist path')
+  plist_parser.add_argument('-o', dest='output', help='The output plist dir')
+
+  # Directory Structure Parser
+  dir_struct_parser = subparsers.add_parser('structure',
+                      help='Creates the directory of an iOS application')
+
+  dir_struct_parser.set_defaults(func=GenerateProjectStructure)
+
+  dir_struct_parser.add_argument('-d', dest='dir', help='Out directory')
+  dir_struct_parser.add_argument('-n', dest='name', help='App name')
+
+  # Code Signing
+  code_signing_parser = subparsers.add_parser('codesign',
+                        help='Code sign the specified application')
+
+  code_signing_parser.set_defaults(func=PerformCodeSigning)
+
+  code_signing_parser.add_argument('-p', dest='application_path', required=True,
+                                   help='The application path')
+  code_signing_parser.add_argument('-i', dest='identity', required=True,
+                                   help='The code signing identity to use')
+  code_signing_parser.add_argument('-e', dest='entitlements_path',
+                                   required=True,
+                                   help='The path to the entitlements .xcent')
+
+  # Engage!
+  args = parser.parse_args()
+  return args.func(args)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/config/ios/ios_sdk.gni b/build/config/ios/ios_sdk.gni
index cb2708b..ebbb7c9 100644
--- a/build/config/ios/ios_sdk.gni
+++ b/build/config/ios/ios_sdk.gni
@@ -1,4 +1,4 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
@@ -7,14 +7,16 @@
   # 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
+  use_ios_simulator = target_cpu == "x86" || target_cpu == "x64"
 
   # Version of iOS that we're targeting.
-  ios_deployment_target = "6.0"
+  ios_deployment_target = "7.0"
+
+  # The iOS Code signing identity to use
+  # TODO(GYP), TODO(sdfresne): Consider having a separate
+  # ios_enable_code_signing_flag=<bool> flag to make the invocation clearer.
+  ios_enable_code_signing = true
+  ios_code_signing_identity = ""
 }
 
 if (ios_sdk_path == "") {
@@ -28,3 +30,24 @@
       exec_script("ios_sdk.py", [ _ios_sdk_to_query ], "list lines")
   ios_sdk_path = _ios_sdk_result[0]
 }
+
+if (use_ios_simulator) {
+  # Always disable code signing on the simulator
+  ios_enable_code_signing = false
+  ios_code_signing_identity = ""
+}
+
+if (ios_enable_code_signing) {
+  # If an identity is not provided, look for one on the host
+  if (ios_code_signing_identity == "") {
+    _ios_identities = exec_script("find_signing_identity.py", [], "list lines")
+    ios_code_signing_identity = _ios_identities[0]
+  }
+
+  if (ios_code_signing_identity == "") {
+    print("Tried to prepare a device build without specifying a code signing")
+    print("identity and could not detect one automatically either.")
+    print("TIP: Simulator builds dont require code signing...")
+    assert(false)
+  }
+}
diff --git a/build/config/ios/ios_sim.py b/build/config/ios/ios_sim.py
new file mode 100755
index 0000000..371719d
--- /dev/null
+++ b/build/config/ios/ios_sim.py
@@ -0,0 +1,106 @@
+#!/usr/bin/python
+# 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.
+
+import argparse
+import errno
+import os
+import subprocess
+import sys
+import re
+
+SIMCTL_PATH = [
+  '/usr/bin/env',
+  'xcrun',
+  'simctl',
+]
+
+PLIST_BUDDY_PATH = [
+  '/usr/bin/env',
+  'xcrun',
+  'PlistBuddy',
+]
+
+
+def ApplicationIdentifier(path):
+  identifier = subprocess.check_output(PLIST_BUDDY_PATH + [
+    '-c',
+    'Print CFBundleIdentifier',
+    '%s/Info.plist' % path,
+  ])
+  return identifier.strip()
+
+
+def Install(args):
+  return subprocess.check_call(SIMCTL_PATH + [
+    'install',
+    'booted',
+    args.path,
+  ])
+
+
+def InstallLaunchAndWait(args, wait):
+  res = Install(args)
+
+  if res != 0:
+    return res
+
+  identifier = ApplicationIdentifier(args.path)
+
+  launch_args = [ 'launch' ]
+
+  if wait:
+    launch_args += [ '-w' ]
+
+  launch_args += [
+    'booted',
+    identifier,
+  ]
+
+  return subprocess.check_output(SIMCTL_PATH + launch_arg).strip()
+
+
+def Launch(args):
+  InstallLaunchAndWait(args, False)
+
+
+def Debug(args):
+  launch_res = InstallLaunchAndWait(args, True)
+  launch_pid = re.search('.*: (\d+)', launch_res).group(1)
+  return os.system(' '.join([
+    '/usr/bin/env',
+    'xcrun',
+    'lldb',
+    '-s',
+    os.path.join(os.path.dirname(__file__), 'lldb_start_commands.txt'),
+    '-p',
+    launch_pid,
+  ]))
+
+
+def main():
+  parser = argparse.ArgumentParser(description='A script that launches an'
+                                   ' application in the simulator and attaches'
+                                   ' the debugger to the same')
+
+  parser.add_argument('-p', dest='path', required=True,
+                      help='Path the the simulator application')
+
+  subparsers = parser.add_subparsers()
+
+  launch_parser = subparsers.add_parser('launch', help='Launch')
+  launch_parser.set_defaults(func=Launch)
+
+  install_parser = subparsers.add_parser('install', help='Install')
+  install_parser.set_defaults(func=Install)
+
+  debug_parser = subparsers.add_parser('debug', help='Debug')
+  debug_parser.set_defaults(func=Debug)
+
+  args = parser.parse_args()
+  return args.func(args)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/config/ios/lldb_start_commands.txt b/build/config/ios/lldb_start_commands.txt
new file mode 100644
index 0000000..42e0b14
--- /dev/null
+++ b/build/config/ios/lldb_start_commands.txt
@@ -0,0 +1,4 @@
+breakpoint set --name UIApplicationMain
+breakpoint set --name objc_exception_throw
+continue
+script print "........ Debugger break on main() ........"
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
new file mode 100644
index 0000000..c18c065
--- /dev/null
+++ b/build/config/ios/rules.gni
@@ -0,0 +1,191 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+ios_app_script = "//build/config/ios/ios_app.py"
+
+template("code_sign_ios") {
+  assert(defined(invoker.entitlements_path),
+         "The path to the entitlements .xcent file")
+  assert(defined(invoker.identity), "The code signing identity")
+  assert(defined(invoker.application_path), "The application to code sign")
+  assert(defined(invoker.deps))
+
+  action(target_name) {
+    sources = [
+      invoker.entitlements_path,
+    ]
+
+    _application_path = invoker.application_path
+
+    script = ios_app_script
+
+    outputs = [
+      "$_application_path/_CodeSignature/CodeResources",
+    ]
+
+    args = [
+      "codesign",
+      "-p",
+      rebase_path(invoker.application_path, root_build_dir),
+      "-i",
+      invoker.identity,
+      "-e",
+      rebase_path(invoker.entitlements_path, root_build_dir),
+    ]
+
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "public_deps",
+                             "testonly",
+                           ])
+  }
+}
+
+# TODO(GYP), TODO(dpranke): Should this be part of ios_app?
+template("resource_copy_ios") {
+  assert(defined(invoker.resources),
+         "The source list of resources to copy over")
+  assert(defined(invoker.bundle_directory),
+         "The directory within the bundle to place the sources in")
+  assert(defined(invoker.app_name), "The name of the application")
+
+  _bundle_directory = invoker.bundle_directory
+  _app_name = invoker.app_name
+  _resources = invoker.resources
+
+  copy(target_name) {
+    set_sources_assignment_filter([])
+    sources = _resources
+    outputs = [
+      "$root_build_dir/$_app_name.app/$_bundle_directory/{{source_file_part}}",
+    ]
+  }
+}
+
+template("ios_app") {
+  assert(defined(invoker.deps),
+         "Dependencies must be specified for $target_name")
+  assert(defined(invoker.info_plist),
+         "The application plist file must be specified for $target_name")
+  assert(defined(invoker.entitlements_path),
+         "The entitlements path must be specified for $target_name")
+  assert(defined(invoker.code_signing_identity),
+         "The code_signing_identity must be specified for $target_name")
+
+  # We just create a variable so we can use the same in interpolation
+  if (defined(invoker.app_name)) {
+    _app_name = invoker.app_name
+  } else {
+    _app_name = target_name
+  }
+
+  forward_variables_from(invoker, [ "testonly" ])
+
+  plist_gen_target_name = target_name + "_plist"
+  bin_gen_target_name = target_name + "_bin"
+  group_target_name = target_name
+
+  # Generate the executable
+  executable(bin_gen_target_name) {
+    visibility = [ ":$group_target_name" ]
+
+    output_name = "${_app_name}.app/${_app_name}"
+
+    forward_variables_from(invoker,
+                           [
+                             "all_dependent_configs",
+                             "allow_circular_includes_from",
+                             "cflags",
+                             "cflags_c",
+                             "cflags_cc",
+                             "cflags_objc",
+                             "cflags_objcc",
+                             "configs",
+                             "check_includes",
+                             "data",
+                             "data_deps",
+                             "defines",
+                             "include_dirs",
+                             "ldflags",
+                             "public",
+                             "public_configs",
+                             "public_deps",
+                             "sources",
+                           ])
+
+    if (defined(invoker.libs)) {
+      libs = invoker.libs
+    } else {
+      libs = []
+    }
+    libs += [
+      "UIKit.framework",
+      "QuartzCore.framework",
+      "OpenGLES.framework",
+    ]
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    } else {
+      deps = []
+    }
+    deps += [ ":$plist_gen_target_name" ]
+  }
+
+  # Process the Info.plist
+  action(plist_gen_target_name) {
+    visibility = [
+      ":$group_target_name",
+      ":$bin_gen_target_name",
+    ]
+
+    script = ios_app_script
+
+    sources = [
+      invoker.info_plist,
+    ]
+    outputs = [
+      "$root_build_dir/${_app_name}.app/Info.plist",
+    ]
+
+    args = [
+      "plist",
+      "-i",
+      rebase_path(invoker.info_plist, root_build_dir),
+      "-o",
+      rebase_path("$root_build_dir/${_app_name}.app"),
+    ]
+  }
+
+  # Perform Code Signing
+  entitlements_path = invoker.entitlements_path
+  if (invoker.code_signing_identity != "") {
+    code_sign_gen_target_name = target_name + "_codesign"
+    code_sign_ios(code_sign_gen_target_name) {
+      visibility = [ ":$target_name" ]
+
+      identity = invoker.code_signing_identity
+      application_path = "$root_build_dir/$app_name.app"
+      deps = [
+        ":$bin_gen_target_name",
+        ":$plist_gen_target_name",
+      ]
+    }
+  } else {
+    # This avoids a potential unused variable warning in the caller.
+    entitlements_path = entitlements_path
+  }
+
+  # Top level group
+  group(target_name) {
+    deps = [
+      ":$bin_gen_target_name",
+      ":$plist_gen_target_name",
+    ]
+    if (invoker.code_signing_identity != "") {
+      deps += [ ":$code_sign_gen_target_name" ]
+    }
+  }
+}
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 3d65937..a19b8f1 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -6,28 +6,20 @@
 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" ])
+# This is included by reference in the //build/config/compiler config that
+# is applied to all targets. It is here to separate out the logic that is
+# Linux-only. This is not applied to Android, but is applied to ChromeOS.
+config("compiler") {
+  cflags = [ "-pthread" ]
+  ldflags = [ "-pthread" ]
+}
 
-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") ]
-  }
-
+# This is included by reference in the //build/config/compiler:runtime_library
+# config that is applied to all targets. It is here to separate out the logic
+# that is Linux-only. Please see that target for advice on what should go in
+# :runtime_library vs. :compiler.
+config("runtime_library") {
   # Set here because OS_CHROMEOS cannot be autodetected in build_config.h like
   # OS_LINUX and the like.
   if (is_chromeos) {
@@ -35,26 +27,9 @@
   }
 }
 
-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") {
+  visibility = [ "//build/linux:fontconfig" ]
+
   libs = [ "fontconfig" ]
 }
 
@@ -85,14 +60,8 @@
   packages = [ "dbus-1" ]
 }
 
-if (use_evdev_gestures) {
-  pkg_config("libevdev-cros") {
-    packages = [ "libevdev-cros" ]
-  }
-
-  pkg_config("libgestures") {
-    packages = [ "libgestures" ]
-  }
+pkg_config("libffi") {
+  packages = [ "libffi" ]
 }
 
 config("x11") {
@@ -146,107 +115,40 @@
 }
 
 # CrOS doesn't install GTK, gconf or any gnome packages.
-if (!is_chromeos) {
+if (!is_chromeos && use_gconf) {
   # 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("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") {
+      cflags = [
+        # glib uses the pre-c++11 typedef-as-static_assert hack.
+        "-Wno-unused-local-typedef",
+
+        # G_DEFINE_TYPE automatically generates a *get_instance_private
+        # inline function after glib 2.37. That's unused. Prevent to
+        # complain about it.
+        "-Wno-unused-function",
+      ]
+    }
+
     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/gtk2/BUILD.gn
similarity index 81%
rename from build/config/linux/gtk/BUILD.gn
rename to build/config/linux/gtk2/BUILD.gn
index 9c9c696..e333e24 100644
--- a/build/config/linux/gtk/BUILD.gn
+++ b/build/config/linux/gtk2/BUILD.gn
@@ -6,12 +6,12 @@
 
 assert(is_linux, "This file should only be referenced on Linux")
 
-# Depend on //build/config/linux/gtk to use GTK.
+# Depend on //build/config/linux/gtk2 to use GTKv2.
 #
 # 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") {
+pkg_config("gtk2_internal_config") {
   # Gtk requires gmodule, but it does not list it as a dependency in some
   # misconfigured systems.
   packages = [
@@ -23,7 +23,7 @@
 
 # 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") {
+group("gtk2") {
   visibility = [
     "//chrome/browser/ui/libgtk2ui",
     "//gpu/gles2_conform_support:gles2_conform_test_windowless",
@@ -31,15 +31,15 @@
     "//remoting/host/it2me:remote_assistance_host",
     "//remoting/host:remoting_me2me_host_static",
   ]
-  public_configs = [ ":gtk_internal_config" ]
+  public_configs = [ ":gtk2_internal_config" ]
 }
 
 # Depend on "gtkprint" to get this.
-pkg_config("gtkprint_internal_config") {
+pkg_config("gtkprint2_internal_config") {
   packages = [ "gtk+-unix-print-2.0" ]
 }
 
-group("gtkprint") {
+group("gtkprint2") {
   visibility = [ "//chrome/browser/ui/libgtk2ui" ]
-  public_configs = [ ":gtkprint_internal_config" ]
+  public_configs = [ ":gtkprint2_internal_config" ]
 }
diff --git a/build/config/linux/gtk/BUILD.gn b/build/config/linux/gtk3/BUILD.gn
similarity index 77%
copy from build/config/linux/gtk/BUILD.gn
copy to build/config/linux/gtk3/BUILD.gn
index 9c9c696..b61ef94 100644
--- a/build/config/linux/gtk/BUILD.gn
+++ b/build/config/linux/gtk3/BUILD.gn
@@ -6,24 +6,24 @@
 
 assert(is_linux, "This file should only be referenced on Linux")
 
-# Depend on //build/config/linux/gtk to use GTK.
+# Depend on //build/config/linux/gtk3 to use GTKv3.
 #
 # 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") {
+pkg_config("gtk3_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",
+    "gtk+-3.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") {
+group("gtk3") {
   visibility = [
     "//chrome/browser/ui/libgtk2ui",
     "//gpu/gles2_conform_support:gles2_conform_test_windowless",
@@ -31,15 +31,15 @@
     "//remoting/host/it2me:remote_assistance_host",
     "//remoting/host:remoting_me2me_host_static",
   ]
-  public_configs = [ ":gtk_internal_config" ]
+  public_configs = [ ":gtk3_internal_config" ]
 }
 
 # Depend on "gtkprint" to get this.
-pkg_config("gtkprint_internal_config") {
-  packages = [ "gtk+-unix-print-2.0" ]
+pkg_config("gtkprint3_internal_config") {
+  packages = [ "gtk+-unix-print-3.0" ]
 }
 
-group("gtkprint") {
+group("gtkprint3") {
   visibility = [ "//chrome/browser/ui/libgtk2ui" ]
-  public_configs = [ ":gtkprint_internal_config" ]
+  public_configs = [ ":gtkprint3_internal_config" ]
 }
diff --git a/build/config/linux/pkg-config.py b/build/config/linux/pkg-config.py
index fadcc0b..3ebc13d 100644
--- a/build/config/linux/pkg-config.py
+++ b/build/config/linux/pkg-config.py
@@ -153,7 +153,7 @@
 
 try:
   flag_string = subprocess.check_output(
-      [ options.pkg_config, "--cflags", "--libs-only-l", "--libs-only-L" ] +
+      [ options.pkg_config, "--cflags", "--libs" ] +
       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
diff --git a/build/config/linux/pkg_config.gni b/build/config/linux/pkg_config.gni
index 34ed1af..914ca8d 100644
--- a/build/config/linux/pkg_config.gni
+++ b/build/config/linux/pkg_config.gni
@@ -73,11 +73,10 @@
       ldflags = pkgresult[4]
     }
 
-    if (defined(invoker.defines)) {
-      defines = invoker.defines
-    }
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
-    }
+    forward_variables_from(invoker,
+                           [
+                             "defines",
+                             "visibility",
+                           ])
   }
 }
diff --git a/build/config/mac/BUILD.gn b/build/config/mac/BUILD.gn
index 9288add..af1fbbc 100644
--- a/build/config/mac/BUILD.gn
+++ b/build/config/mac/BUILD.gn
@@ -3,34 +3,86 @@
 # found in the LICENSE file.
 
 import("//build/config/sysroot.gni")
+import("//build/config/mac/mac_sdk.gni")
 
-config("sdk") {
+# This is included by reference in the //build/config/compiler config that
+# is applied to all targets. It is here to separate out the logic.
+#
+# This is applied to BOTH desktop Mac and iOS targets.
+config("compiler") {
+  # 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",
+    ]
+  } else if (current_cpu == "arm") {
+    # TODO(GYP): we may need to distinguish between "arm64", "armv7",
+    # and "armv7s" for iOS, and hence need multiple current_cpu values
+    # rather than just "arm".
+    common_mac_flags += [
+      "-arch",
+      "arm64",
+      "-arch",
+      "armv7",
+    ]
+  }
+
+  asmflags = common_mac_flags
+  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" ]
+  cflags_objc = cflags_c
+
+  ldflags = common_mac_flags
+}
+
+# This is included by reference in the //build/config/compiler:runtime_library
+# config that is applied to all targets. It is here to separate out the logic
+# that is Mac-only. Please see that target for advice on what should go in
+# :runtime_library vs. :compiler.
+config("runtime_library") {
   common_flags = [
     "-isysroot",
     sysroot,
-    "-mmacosx-version-min=10.6",
+    "-mmacosx-version-min=$mac_deployment_target",
   ]
 
+  asmflags = common_flags
   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.",
+  ldflags = []
 
-    # Path for loading shared libraries for unbundled binaries.
-    "-Wl,-rpath,@loader_path/.",
+  if (is_component_build) {
+    ldflags += [
+      # 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/../../..",
-  ]
+      # 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") {
+  # Remove this when targeting >=10.7 since it is the default in that config.
   ldflags = [ "-Wl,-pie" ]  # Position independent.
 }
diff --git a/build/config/mac/mac_app.py b/build/config/mac/mac_app.py
new file mode 100644
index 0000000..70c313a
--- /dev/null
+++ b/build/config/mac/mac_app.py
@@ -0,0 +1,99 @@
+# 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.
+
+import argparse
+import errno
+import os
+import subprocess
+import sys
+
+def MakeDirectories(path):
+  try:
+    os.makedirs(path)
+  except OSError as exc:
+    if exc.errno == errno.EEXIST and os.path.isdir(path):
+      return 0
+    else:
+      return -1
+
+  return 0
+
+
+def ProcessInfoPlist(args):
+  output_plist_file = os.path.abspath(os.path.join(args.output, 'Info.plist'))
+  return subprocess.check_call([
+    '/usr/bin/env',
+    'xcrun',
+    'plutil'
+    '-convert',
+    'binary1',
+    '-o',
+    output_plist_file,
+    '--',
+    args.input,
+  ])
+
+
+def ProcessNIB(args):
+  output_nib_file = os.path.join(os.path.abspath(args.output),
+      "%s.nib" % os.path.splitext(os.path.basename(args.input))[0])
+
+  return subprocess.check_call([
+    '/usr/bin/env',
+    'xcrun',
+    'ibtool',
+    '--module',
+    args.module,
+    '--auto-activate-custom-fonts',
+    '--target-device',
+    'mac',
+    '--compile',
+    output_nib_file,
+    os.path.abspath(args.input),
+  ])
+
+
+def GenerateProjectStructure(args):
+  application_path = os.path.join( args.dir, args.name + ".app", "Contents" )
+  return MakeDirectories( application_path )
+
+
+def main():
+  parser = argparse.ArgumentParser(description='A script that aids in '
+                                   'the creation of an Mac application')
+
+  subparsers = parser.add_subparsers()
+
+  # Plist Parser
+  plist_parser = subparsers.add_parser('plist',
+                                       help='Process the Info.plist')
+  plist_parser.set_defaults(func=ProcessInfoPlist)
+
+  plist_parser.add_argument('-i', dest='input', help='The input plist path')
+  plist_parser.add_argument('-o', dest='output', help='The output plist dir')
+
+  # NIB Parser
+  plist_parser = subparsers.add_parser('nib',
+                                       help='Process a NIB file')
+  plist_parser.set_defaults(func=ProcessNIB)
+
+  plist_parser.add_argument('-i', dest='input', help='The input nib path')
+  plist_parser.add_argument('-o', dest='output', help='The output nib dir')
+  plist_parser.add_argument('-m', dest='module', help='The module name')
+
+  # Directory Structure Parser
+  dir_struct_parser = subparsers.add_parser('structure',
+                      help='Creates the directory of an Mac application')
+
+  dir_struct_parser.set_defaults(func=GenerateProjectStructure)
+
+  dir_struct_parser.add_argument('-d', dest='dir', help='Out directory')
+  dir_struct_parser.add_argument('-n', dest='name', help='App name')
+
+  args = parser.parse_args()
+  return args.func(args)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni
index 600085e..8767aa4 100644
--- a/build/config/mac/mac_sdk.gni
+++ b/build/config/mac/mac_sdk.gni
@@ -6,9 +6,12 @@
 
 declare_args() {
   # Minimum supported version of the Mac SDK.
-  mac_sdk_min = "10.6"
+  mac_sdk_min = "10.10"
 
-  # Path to a specific version of the Mac SDKJ, not including a backslash at
+  # Minimum supported version of OSX.
+  mac_deployment_target = "10.6"
+
+  # Path to a specific version of the Mac SDK, 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 = ""
@@ -31,11 +34,5 @@
     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/mac/rules.gni b/build/config/mac/rules.gni
new file mode 100644
index 0000000..32f3d99
--- /dev/null
+++ b/build/config/mac/rules.gni
@@ -0,0 +1,212 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mac_app_script = "//build/config/mac/mac_app.py"
+
+template("code_sign_mac") {
+  assert(defined(invoker.entitlements_path),
+         "The path to the entitlements .xcent file")
+  assert(defined(invoker.identity), "The code signing identity")
+  assert(defined(invoker.application_path), "The application to code sign")
+  assert(defined(invoker.deps))
+
+  action(target_name) {
+    sources = [
+      invoker.entitlements_path,
+    ]
+
+    _application_path = invoker.application_path
+
+    script = mac_app_script
+
+    outputs = [
+      "$_application_path/_CodeSignature/CodeResources",
+    ]
+
+    args = [
+      "codesign",
+      "-p",
+      rebase_path(invoker.application_path, root_build_dir),
+      "-i",
+      invoker.identity,
+      "-e",
+      rebase_path(invoker.entitlements_path, root_build_dir),
+    ]
+
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "public_deps",
+                             "visibility",
+                           ])
+  }
+}
+
+template("process_nibs_mac") {
+  assert(defined(invoker.sources), "The nib sources must be specified")
+  assert(defined(invoker.module), "The nib module must be specified")
+  assert(defined(invoker.output_dir), "The output directory must be specified")
+
+  action_foreach(target_name) {
+    sources = invoker.sources
+
+    script = mac_app_script
+
+    invoker_out_dir = invoker.output_dir
+
+    outputs = [
+      "$root_build_dir/$invoker_out_dir/{{source_name_part}}.nib",
+    ]
+
+    args = [
+      "nib",
+      "-i",
+      "{{source}}",
+      "-o",
+      invoker_out_dir,
+      "-m",
+      invoker.module,
+    ]
+  }
+
+  forward_variables_from(invoker,
+                         [
+                           "deps",
+                           "public_deps",
+                           "visibility",
+                         ])
+}
+
+template("resource_copy_mac") {
+  assert(defined(invoker.resources),
+         "The source list of resources to copy over")
+  assert(defined(invoker.bundle_directory),
+         "The directory within the bundle to place the sources in")
+
+  if (defined(invoker.app_name)) {
+    _app_name = invoker.app_name
+  } else {
+    _app_name = target_name
+  }
+
+  _bundle_directory = invoker.bundle_directory
+  _resources = invoker.resources
+
+  copy(target_name) {
+    set_sources_assignment_filter([])
+    sources = _resources
+    outputs = [
+      "$root_build_dir/$_app_name.app/$_bundle_directory/Contents/Resources/{{source_file_part}}",
+    ]
+  }
+}
+
+template("mac_app") {
+  assert(defined(invoker.deps),
+         "Dependencies must be specified for $target_name")
+  assert(defined(invoker.info_plist),
+         "The application plist file must be specified for $target_name")
+  assert(defined(invoker.xibs),
+         "The list of XIB files must be specified for $target_name")
+
+  group_gen_target_name = target_name
+  copy_all_target_name = target_name + "_all_copy"
+
+  # We just create a variable so we can use the same in interpolation
+  if (defined(invoker.app_name)) {
+    _app_name = invoker.app_name
+  } else {
+    _app_name = target_name
+  }
+
+  # Generate the executable
+  bin_gen_target_name = target_name + "_bin"
+  executable(bin_gen_target_name) {
+    visibility = [ ":$group_gen_target_name" ]
+    deps = invoker.deps
+    output_name = app_name
+  }
+
+  # Process the Info.plist
+  plist_gen_target_name = target_name + "_plist"
+
+  action(plist_gen_target_name) {
+    visibility = [ ":$group_gen_target_name" ]
+    script = mac_app_script
+
+    sources = [
+      invoker.info_plist,
+    ]
+    outputs = [
+      "$root_build_dir/Info.plist",
+    ]
+
+    args = [
+      "plist",
+      "-i",
+      rebase_path(invoker.info_plist, root_build_dir),
+      "-o",
+      rebase_path(root_build_dir),
+    ]
+  }
+
+  # Copy the generated binaries and assets to their appropriate locations
+  copy_plist_gen_target_name = target_name + "_plist_copy"
+  copy(copy_plist_gen_target_name) {
+    visibility = [ ":$group_gen_target_name" ]
+    sources = [
+      "$root_build_dir/Info.plist",
+    ]
+
+    outputs = [
+      "$root_build_dir/$app_name.app/Contents/{{source_file_part}}",
+    ]
+
+    deps = [
+      ":$plist_gen_target_name",
+    ]
+  }
+
+  copy_bin_target_name = target_name + "_bin_copy"
+  copy(copy_bin_target_name) {
+    visibility = [ ":$group_gen_target_name" ]
+    sources = [
+      "$root_build_dir/$app_name",
+    ]
+
+    outputs = [
+      "$root_build_dir/$app_name.app/Contents/MacOS/{{source_file_part}}",
+    ]
+
+    deps = [
+      ":$bin_gen_target_name",
+    ]
+  }
+
+  copy_xib_target_name = target_name + "_xib_copy"
+  process_nibs_mac(copy_xib_target_name) {
+    visibility = [ ":$group_gen_target_name" ]
+    sources = invoker.xibs
+    module = app_name
+    output_dir = "$app_name.app/Contents/Resources"
+  }
+
+  group(copy_all_target_name) {
+    visibility = [ ":$group_gen_target_name" ]
+    deps = [
+      ":$copy_bin_target_name",
+      ":$copy_plist_gen_target_name",
+      ":$copy_xib_target_name",
+      ":$struct_gen_target_name",
+    ]
+  }
+
+  # Top level group
+
+  group(group_gen_target_name) {
+    deps = [
+      ":$copy_all_target_name",
+    ]
+  }
+}
diff --git a/build/config/nacl/BUILD.gn b/build/config/nacl/BUILD.gn
new file mode 100644
index 0000000..d7b22ec
--- /dev/null
+++ b/build/config/nacl/BUILD.gn
@@ -0,0 +1,143 @@
+# Copyright (c) 2014 The Native Client 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/nacl/config.gni")
+
+# Native Client Definitions
+config("nacl_defines") {
+  if (is_linux || is_android || is_nacl) {
+    defines = [
+      "_POSIX_C_SOURCE=199506",
+      "_XOPEN_SOURCE=600",
+      "_GNU_SOURCE=1",
+      "__STDC_LIMIT_MACROS=1",
+    ]
+  } else if (is_win) {
+    defines = [ "__STDC_LIMIT_MACROS=1" ]
+  }
+
+  if (current_cpu == "pnacl" && !is_nacl_nonsfi) {
+    # TODO: Remove the following definition once NACL_BUILD_ARCH and
+    # NACL_BUILD_SUBARCH are defined by the PNaCl toolchain.
+    defines += [ "NACL_BUILD_ARCH=pnacl" ]
+  }
+}
+
+config("nexe_defines") {
+  defines = [
+    "DYNAMIC_ANNOTATIONS_ENABLED=1",
+    "DYNAMIC_ANNOTATIONS_PREFIX=NACL_",
+  ]
+}
+
+config("nacl_warnings") {
+  if (is_win) {
+    # Some NaCl code uses forward declarations of static const variables,
+    # with initialized definitions later on.  (The alternative would be
+    # many, many more forward declarations of everything used in that
+    # const variable's initializer before the definition.)  The Windows
+    # compiler is too stupid to notice that there is an initializer later
+    # in the file, and warns about the forward declaration.
+    cflags = [ "/wd4132" ]
+  }
+}
+
+# The base target that all targets in the NaCl build should depend on.
+# This allows configs to be modified for everything in the NaCl build, even when
+# the NaCl build is composed into the Chrome build.  (GN has no functionality to
+# add flags to everything in //native_client, having a base target works around
+# that limitation.)
+source_set("nacl_base") {
+  public_configs = [
+    ":nacl_defines",
+    ":nacl_warnings",
+  ]
+  if (current_os == "nacl") {
+    public_configs += [ ":nexe_defines" ]
+  }
+}
+
+config("compiler") {
+  configs = []
+  cflags = []
+  ldflags = []
+  libs = []
+
+  if (is_clang && current_cpu != "pnacl") {
+    # -no-integrated-as is the default in nacl-clang for historical
+    # compatibility with inline assembly code and so forth.  But there
+    # are no such cases in Chromium code, and -integrated-as is nicer in
+    # general.  Moreover, the IRT must be built using LLVM's assembler
+    # on x86-64 to preserve sandbox base address hiding.  Use it
+    # everywhere for consistency (and possibly quicker builds).
+    cflags += [ "-integrated-as" ]
+  }
+  if (is_nacl_nonsfi) {
+    cflags += [ "--pnacl-allow-translate" ]
+    ldflags += [
+      "--pnacl-allow-translate",
+      "--pnacl-allow-native",
+      "-Wl,--noirt",
+      "-Wt,--noirt",
+      "-Wt,--noirtshim",
+
+      # The clang driver automatically injects -lpthread when using libc++, but
+      # the toolchain doesn't have it yet.  To get around this, use
+      # -nodefaultlibs and make each executable target depend on
+      # "//native_client/src/nonsfi/irt:nacl_sys_private".
+      "-nodefaultlibs",
+    ]
+    libs += [
+      "c++",
+      "m",
+      "c",
+      "pnaclmm",
+    ]
+    include_dirs = [ "//native_client/src/public/linux_syscalls" ]
+  }
+
+  asmflags = cflags
+}
+
+config("compiler_codegen") {
+  cflags = []
+
+  if (is_nacl_irt) {
+    cflags += [
+      # A debugger should be able to unwind IRT call frames.  This is
+      # the default behavior on x86-64 and when compiling C++ with
+      # exceptions enabled; the change is for the benefit of x86-32 C.
+      # The frame pointer is unnecessary when unwind tables are used.
+      "-fasynchronous-unwind-tables",
+      "-fomit-frame-pointer",
+    ]
+
+    if (current_cpu == "x86") {
+      # The x86-32 IRT needs to be callable with an under-aligned
+      # stack; so we disable SSE instructions, which can fault on
+      # misaligned addresses.  See
+      # https://code.google.com/p/nativeclient/issues/detail?id=3935
+      cflags += [
+        "-mstackrealign",
+        "-mno-sse",
+      ]
+    }
+  }
+
+  asmflags = cflags
+}
+
+config("irt_optimize") {
+  cflags = [
+    # Optimize for space, keep the IRT nexe small.
+    "-Os",
+
+    # These are omitted from non-IRT libraries to keep the libraries
+    # themselves small.
+    "-ffunction-sections",
+    "-fdata-sections",
+  ]
+
+  ldflags = [ "-Wl,--gc-sections" ]
+}
diff --git a/build/config/nacl/config.gni b/build/config/nacl/config.gni
new file mode 100644
index 0000000..6abd8aa
--- /dev/null
+++ b/build/config/nacl/config.gni
@@ -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.
+
+declare_args() {
+  # Native Client supports both Newlib and Glibc C libraries where Newlib
+  # is assumed to be the default one; use this to determine whether Glibc
+  # is being used instead.
+  is_nacl_glibc = false
+}
+
+nacl_toolchain_dir = "//native_client/toolchain/${host_os}_x86"
+
+if (is_nacl_glibc) {
+  if (current_cpu == "x86" || current_cpu == "x64") {
+    nacl_toolchain_package = "nacl_x86_glibc"
+  } else if (current_cpu == "arm") {
+    nacl_toolchain_package = "nacl_arm_glibc"
+  }
+} else {
+  nacl_toolchain_package = "pnacl_newlib"
+}
+
+if (current_cpu == "pnacl") {
+  nacl_tuple = "pnacl"
+} else if (current_cpu == "x86" || current_cpu == "x64") {
+  nacl_tuple = "x86_64-nacl"
+} else if (current_cpu == "arm") {
+  nacl_tuple = "arm-nacl"
+} else if (current_cpu == "mipsel") {
+  nacl_tuple = "mipsel-nacl"
+}
+
+nacl_toolchain_bindir = "${nacl_toolchain_dir}/${nacl_toolchain_package}/bin"
+nacl_toolchain_tooldir =
+    "${nacl_toolchain_dir}/${nacl_toolchain_package}/${nacl_tuple}"
+nacl_toolprefix = "${nacl_toolchain_bindir}/${nacl_tuple}-"
+
+nacl_irt_toolchain = "//build/toolchain/nacl:irt_" + target_cpu
+is_nacl_irt = current_toolchain == nacl_irt_toolchain
+
+# Non-SFI mode is a lightweight sandbox used by Chrome OS for running ARC
+# applications.
+nacl_nonsfi_toolchain = "//build/toolchain/nacl:newlib_pnacl_nonsfi"
+is_nacl_nonsfi = current_toolchain == nacl_nonsfi_toolchain
diff --git a/build/config/nacl/rules.gni b/build/config/nacl/rules.gni
new file mode 100644
index 0000000..5801d45
--- /dev/null
+++ b/build/config/nacl/rules.gni
@@ -0,0 +1,155 @@
+# Copyright 2015 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//build/config/nacl/config.gni")
+
+# Generate a nmf file
+#
+# Native Client Manifest (nmf) is a JSON file that tells the browser where to
+# download and load Native Client application files and libraries.
+#
+# Variables:
+#   executables: .nexe/.pexe/.bc executables to generate nmf for
+#   lib_prefix: path to prepend to shared libraries in the nmf
+#   nmf: the name and the path of the output file
+#   nmfflags: additional flags for the nmf generator
+#   stage_dependencies: directory for staging libraries
+template("generate_nmf") {
+  assert(defined(invoker.executables), "Must define executables")
+  assert(defined(invoker.nmf), "Must define nmf")
+
+  action(target_name) {
+    nmfflags = []
+
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "data_deps",
+                             "executables",
+                             "lib_prefix",
+                             "nmf",
+                             "nmfflags",
+                             "public_deps",
+                             "stage_dependencies",
+                             "testonly",
+                             "visibility",
+                           ])
+
+    # TODO(phosek): Remove this conditional once
+    # https://bugs.chromium.org/p/nativeclient/issues/detail?id=4339 is
+    # resolved.
+    if (current_cpu == "pnacl") {
+      objdump = rebase_path("${nacl_toolchain_bindir}/x86_64-nacl-objdump")
+    } else {
+      objdump = rebase_path("${nacl_toolprefix}objdump")
+    }
+    if (host_os == "win") {
+      objdump += ".exe"
+    }
+
+    script = "//native_client_sdk/src/tools/create_nmf.py"
+    inputs = [
+      objdump,
+    ]
+    sources = executables
+    outputs = [
+      nmf,
+    ]
+    if (is_nacl_glibc) {
+      if (defined(stage_dependencies)) {
+        nmfflags += [ "--stage-dependencies=" +
+                      rebase_path(stage_dependencies, root_build_dir) ]
+        lib_path = stage_dependencies
+      } else {
+        lib_path = root_build_dir
+      }
+      if (defined(lib_prefix)) {
+        nmfflags += [ "--lib-prefix=" + lib_prefix ]
+        lib_path += "/${lib_prefix}"
+      }
+
+      # NOTE: There is no explicit dependency for the lib32
+      # and lib64 directories created in the product directory.
+      # They are created as a side-effect of nmf creation.
+      nmfflags += [ "--library-path=" + rebase_path(root_out_dir) ]
+      if (current_cpu == "x86") {
+        nmfflags += [ "--library-path=" +
+                      rebase_path("${nacl_toolchain_tooldir}/lib32") ]
+        data = [
+          "${lib_path}/lib32/",
+        ]
+      } else if (current_cpu == "x64") {
+        nmfflags +=
+            [ "--library-path=" + rebase_path("${nacl_toolchain_tooldir}/lib") ]
+        data = [
+          "${lib_path}/lib64/",
+        ]
+      } else {
+        nmfflags +=
+            [ "--library-path=" + rebase_path("${nacl_toolchain_tooldir}/lib") ]
+        data = [
+          "${lib_path}/lib/",
+        ]
+      }
+    }
+    args = [
+             "--no-default-libpath",
+             "--objdump=" + objdump,
+             "--output=" + rebase_path(nmf, root_build_dir),
+           ] + nmfflags + rebase_path(sources, root_build_dir)
+    if (is_nacl_glibc && current_cpu == "arm") {
+      deps += [ "//native_client/src/untrusted/elf_loader:elf_loader" ]
+    }
+  }
+}
+
+# Generate a nmf file for Non-SFI tests
+#
+# Non-SFI tests use a different manifest format from regular Native Client and
+# as such requires a different generator.
+#
+# Variables:
+#   executable: Non-SFI .nexe executable to generate nmf for
+#   nmf: the name and the path of the output file
+template("generate_nonsfi_test_nmf") {
+  assert(defined(invoker.executable), "Must define executable")
+  assert(defined(invoker.nmf), "Must define nmf")
+
+  action(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "data_deps",
+                             "executable",
+                             "nmf",
+                             "testonly",
+                             "public_deps",
+                           ])
+
+    script = "//ppapi/tests/create_nonsfi_test_nmf.py"
+    sources = [
+      executable,
+    ]
+    outputs = [
+      nmf,
+    ]
+
+    # NOTE: We use target_cpu rather than current_cpu on purpose because
+    # current_cpu is always going to be pnacl for Non-SFI, but the Non-SFI
+    # .nexe executable is always translated to run on the target machine.
+    if (target_cpu == "x86") {
+      arch = "x86-32"
+    } else if (target_cpu == "x64") {
+      arch = "x86-64"
+    } else {
+      arch = target_cpu
+    }
+    args = [
+      "--program=" + rebase_path(executable, root_build_dir),
+      "--arch=${arch}",
+      "--output=" + rebase_path(nmf, root_build_dir),
+    ]
+  }
+}
diff --git a/build/config/posix/BUILD.gn b/build/config/posix/BUILD.gn
new file mode 100644
index 0000000..6f65443
--- /dev/null
+++ b/build/config/posix/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sysroot.gni")
+
+assert(is_posix)
+
+# This is included by reference in the //build/config/compiler:runtime_library
+# config that is applied to all targets. It is here to separate out the logic
+# that is Posix-only. Please see that target for advice on what should go in
+# :runtime_library vs. :compiler.
+config("runtime_library") {
+  if (!is_mac && sysroot != "") {
+    # Pass the sysroot to all C compiler variants, the assembler, and linker.
+    cflags = [ "--sysroot=" + sysroot ]
+    asmflags = cflags
+    ldflags = cflags
+
+    # 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") ]
+  }
+}
diff --git a/build/config/linux/sysroot_ld_path.py b/build/config/posix/sysroot_ld_path.py
similarity index 100%
rename from build/config/linux/sysroot_ld_path.py
rename to build/config/posix/sysroot_ld_path.py
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 3972a5c..2adab21 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -2,23 +2,53 @@
 # 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
+import("//build/config/chrome_build.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+
+# Contains the dependencies needed for sanitizers to link into executables and
 # shared_libraries. Unconditionally depend upon this target as it is empty if
-# |is_asan| is false.
+# |is_asan|, |is_lsan|, |is_tsan|, |is_msan| and |use_custom_libcxx| are false.
 group("deps") {
-  if (is_asan) {
+  if (using_sanitizer) {
     public_configs = [ ":sanitizer_options_link_helper" ]
     deps = [
       ":options_sources",
     ]
+
+    if (use_prebuilt_instrumented_libraries) {
+      deps += [ "//third_party/instrumented_libraries:deps" ]
+    }
+    if (use_custom_libcxx) {
+      deps += [ "//buildtools/third_party/libc++:libcxx_proxy" ]
+    }
   }
 }
 
 config("sanitizer_options_link_helper") {
-  ldflags = [
-    "-Wl,-u_sanitizer_options_link_helper",
-    "-fsanitize=address",
-  ]
+  ldflags = [ "-Wl,-u_sanitizer_options_link_helper" ]
+  if (is_asan) {
+    ldflags += [ "-fsanitize=address" ]
+  }
+  if (is_lsan) {
+    ldflags += [ "-fsanitize=leak" ]
+  }
+  if (is_tsan) {
+    ldflags += [ "-fsanitize=thread" ]
+  }
+  if (is_msan) {
+    ldflags += [
+      "-fsanitize=memory",
+
+      # TODO(eugenis): Remove when msan migrates to new ABI (crbug.com/560589).
+      "-pie",
+    ]
+  }
+  if (is_ubsan) {
+    ldflags += [ "-fsanitize=undefined" ]
+  }
+  if (is_ubsan_vptr) {
+    ldflags += [ "-fsanitize=vptr" ]
+  }
 }
 
 source_set("options_sources") {
@@ -30,11 +60,200 @@
     "//build/sanitizers/sanitizer_options.cc",
   ]
 
+  # Don't compile this target with any sanitizer code. It can be called from
+  # the sanitizer runtimes, so instrumenting these functions could cause
+  # recursive calls into the runtime if there is an error.
+  configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ]
+  configs -= [ "//build/config/sanitizers:default_sanitizer_coverage_flags" ]
+
   if (is_asan) {
     sources += [ "//build/sanitizers/asan_suppressions.cc" ]
   }
 
+  if (is_lsan) {
+    sources += [ "//build/sanitizers/lsan_suppressions.cc" ]
+  }
+
   if (is_tsan) {
     sources += [ "//build/sanitizers/tsan_suppressions.cc" ]
   }
 }
+
+# This config is applied by default to all targets. It sets the compiler flags
+# for sanitizer usage, or, if no sanitizer is set, does nothing.
+#
+# This needs to be in a separate config so that targets can opt out of
+# sanitizers if they desire.
+config("default_sanitizer_flags") {
+  cflags = []
+  cflags_cc = []
+  ldflags = []
+  defines = []
+
+  # Only works on Posix-like platforms.
+  # FIXME: this is not true, remove the conditional.
+  if (is_posix) {
+    # Common options for AddressSanitizer, LeakSanitizer, ThreadSanitizer,
+    # MemorySanitizer and non-official CFI builds.
+    if (using_sanitizer || (is_cfi && !is_official_build)) {
+      cflags += [
+        "-fno-omit-frame-pointer",
+        "-gline-tables-only",
+      ]
+    }
+    if (is_asan) {
+      asan_blacklist_path =
+          rebase_path("//tools/memory/asan/blacklist.txt", root_build_dir)
+      cflags += [
+        "-fsanitize=address",
+        "-fsanitize-blacklist=$asan_blacklist_path",
+      ]
+      if (is_android) {
+        # 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",
+        ]
+      } else if (is_mac) {
+        # http://crbug.com/352073
+        cflags += [
+          "-mllvm",
+          "-asan-globals=0",
+        ]
+        # TODO(GYP): deal with mac_bundles.
+      }
+    }
+    if (is_lsan) {
+      cflags += [ "-fsanitize=leak" ]
+    }
+    if (is_tsan) {
+      tsan_blacklist_path =
+          rebase_path("//tools/memory/tsan_v2/ignores.txt", root_build_dir)
+      cflags += [
+        "-fsanitize=thread",
+        "-fsanitize-blacklist=$tsan_blacklist_path",
+      ]
+    }
+    if (is_msan) {
+      msan_blacklist_path =
+          rebase_path("//tools/msan/blacklist.txt", root_build_dir)
+      cflags += [
+        "-fsanitize=memory",
+        "-fsanitize-memory-track-origins=$msan_track_origins",
+        "-fsanitize-blacklist=$msan_blacklist_path",
+
+        # TODO(eugenis): Remove when msan migrates to new ABI (crbug.com/560589).
+        "-fPIC",
+      ]
+    }
+    if (is_ubsan) {
+      ubsan_blacklist_path =
+          rebase_path("//tools/ubsan/blacklist.txt", root_build_dir)
+      cflags += [
+        # Yasm dies with an "Illegal instruction" error when bounds checking is
+        # enabled. See http://crbug.com/489901
+        # "-fsanitize=bounds",
+        "-fsanitize=float-divide-by-zero",
+        "-fsanitize=integer-divide-by-zero",
+        "-fsanitize=null",
+        "-fsanitize=object-size",
+        "-fsanitize=return",
+        "-fsanitize=returns-nonnull-attribute",
+        "-fsanitize=shift-exponent",
+        "-fsanitize=signed-integer-overflow",
+        "-fsanitize=unreachable",
+        "-fsanitize=vla-bound",
+        "-fsanitize-blacklist=$ubsan_blacklist_path",
+
+        # 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",
+      ]
+    }
+    if (is_ubsan_vptr) {
+      ubsan_vptr_blacklist_path =
+          rebase_path("//tools/ubsan/vptr_blacklist.txt", root_build_dir)
+      cflags += [
+        "-fsanitize=vptr",
+        "-fsanitize-blacklist=$ubsan_vptr_blacklist_path",
+      ]
+    }
+    if (is_cfi && !is_nacl) {
+      cfi_blacklist_path =
+          rebase_path("//tools/cfi/blacklist.txt", root_build_dir)
+      cflags += [
+        "-flto",
+        "-fsanitize=cfi-vcall",
+        "-fsanitize=cfi-derived-cast",
+        "-fsanitize=cfi-unrelated-cast",
+        "-fsanitize-blacklist=$cfi_blacklist_path",
+      ]
+      ldflags += [
+        "-flto",
+        "-fsanitize=cfi-vcall",
+        "-fsanitize=cfi-derived-cast",
+        "-fsanitize=cfi-unrelated-cast",
+      ]
+
+      # Apply a lower LTO optimization level as the default is too slow.
+      if (is_linux) {
+        ldflags += [ "-Wl,-plugin-opt,O1" ]
+      } else if (is_mac) {
+        ldflags += [ "-Wl,-mllvm,-O1" ]
+      }
+
+      # Work-around for http://openradar.appspot.com/20356002
+      if (is_mac) {
+        ldflags += [ "-Wl,-all_load" ]
+      }
+
+      # 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).
+      if (current_cpu == "arm") {
+        ldflags += [ "-Wl,-plugin-opt,-function-sections" ]
+      }
+
+      if (use_cfi_diag) {
+        cflags += [
+          "-fno-sanitize-trap=cfi",
+          "-fsanitize-recover=cfi",
+        ]
+        ldflags += [
+          "-fno-sanitize-trap=cfi",
+          "-fsanitize-recover=cfi",
+        ]
+      } else {
+        defines += [ "CFI_ENFORCEMENT" ]
+      }
+    }
+
+    if (use_custom_libcxx) {
+      cflags_cc += [ "-nostdinc++" ]
+      include_dirs = [
+        "//buildtools/third_party/libc++/trunk/include",
+        "//buildtools/third_party/libc++abi/trunk/include",
+      ]
+    }
+  }
+}
+
+config("default_sanitizer_coverage_flags") {
+  cflags = []
+
+  if (use_sanitizer_coverage) {
+    # FIXME: make this configurable.
+    cflags +=
+        [ "-fsanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp" ]
+  }
+}
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni
new file mode 100644
index 0000000..ddf28f1
--- /dev/null
+++ b/build/config/sanitizers/sanitizers.gni
@@ -0,0 +1,90 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+  # 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
+
+  # Compile for Undefined Behaviour Sanitizer to find various types of
+  # undefined behaviour (excludes vptr checks).
+  is_ubsan = false
+
+  # Compile for Undefined Behaviour Sanitizer's vptr checks.
+  is_ubsan_vptr = false
+
+  # 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
+
+  # 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 = false
+
+  # Enable building with SyzyAsan which can find certain types of memory
+  # errors. Only works on Windows. See
+  # https://code.google.com/p/sawbuck/wiki/SyzyASanHowTo
+  is_syzyasan = false
+
+  # Compile with Control Flow Integrity to protect virtual calls and casts.
+  # See http://clang.llvm.org/docs/ControlFlowIntegrity.html
+  is_cfi = false
+
+  # By default, Control Flow Integrity will crash the program if it detects a
+  # violation. Set this to true to print detailed diagnostics instead.
+  use_cfi_diag = false
+
+  # Compile for fuzzing with LLVM LibFuzzer.
+  # See http://www.chromium.org/developers/testing/libfuzzer
+  use_libfuzzer = false
+}
+
+# Args that are in turn dependent on other args must be in a separate
+# declare_args block. User overrides are only applied at the end of a
+# declare_args block.
+declare_args() {
+  # Use libc++ (buildtools/third_party/libc++ and
+  # buildtools/third_party/libc++abi) instead of stdlibc++ as standard library.
+  # This is intended to be used for instrumented builds.
+  use_custom_libcxx =
+      (is_asan && is_linux) || is_tsan || is_msan || is_ubsan || use_libfuzzer
+
+  use_sanitizer_coverage = use_libfuzzer
+}
+
+using_sanitizer =
+    is_asan || is_lsan || is_tsan || is_msan || is_ubsan || is_ubsan_vptr
+
+assert(!using_sanitizer || is_clang,
+       "Sanitizers (is_*san) require setting is_clang = true in 'gn args'")
+
+# MSan only links Chrome properly in release builds (brettw -- 9/1/2015). The
+# same is possibly true for the other non-ASan sanitizers. But regardless of
+# whether it links, one would normally never run a sanitizer in debug mode.
+# Running in debug mode probably indicates you forgot to set the "is_debug =
+# false" flag in the build args. ASan seems to run fine in debug mode.
+#
+# If you find a use-case where you want to compile a sanitizer in debug mode
+# and have verified it works, ask brettw and we can consider removing it from
+# this condition. We may also be able to find another way to enable your case
+# without having people accidentally get broken builds by compiling an
+# unsupported or unadvisable configurations.
+#
+# For one-off testing, just comment this assertion out.
+assert(
+    !is_debug || !(is_msan || is_lsan || is_tsan || is_ubsan || is_ubsan_vptr),
+    "Sanitizers should generally be used in release (set is_debug=false).")
+
+assert(!(is_android && is_asan && !is_component_build),
+       "is_asan on Android requires is_component_build to be set")
diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni
index e5a9c2b..debf771 100644
--- a/build/config/sysroot.gni
+++ b/build/config/sysroot.gni
@@ -11,6 +11,7 @@
   # The absolute path of the sysroot that is applied when compiling using
   # the target toolchain.
   target_sysroot = ""
+  use_sysroot = true
 }
 
 if (current_toolchain == default_toolchain && target_sysroot != "") {
@@ -32,27 +33,23 @@
   } 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.
+} else if (is_linux && !is_chromeos && use_sysroot) {
+  # By default build against a sysroot image downloaded from Cloud Storage
+  # during gclient runhooks.
   if (current_cpu == "x64") {
-    sysroot =
-        rebase_path("//chrome/installer/linux/debian_wheezy_amd64-sysroot")
+    sysroot = rebase_path("//build/linux/debian_wheezy_amd64-sysroot")
   } else if (current_cpu == "x86") {
-    sysroot = rebase_path("//chrome/installer/linux/debian_wheezy_i386-sysroot")
+    sysroot = rebase_path("//build/linux/debian_wheezy_i386-sysroot")
+  } else if (current_cpu == "mipsel") {
+    sysroot = rebase_path("//build/linux/debian_wheezy_mips-sysroot")
+  } else if (current_cpu == "arm") {
+    sysroot = rebase_path("//build/linux/debian_wheezy_arm-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")
diff --git a/build/config/ui.gni b/build/config/ui.gni
index 787e7ef..1fc6d0a 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -2,46 +2,74 @@
 # 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.
+# This file contains UI-related build flags (see features.gni for Chrome
+# feature-related ones). These should theoretically be moved to the ui
+# directory.
 #
 # However, today we have many "bad" dependencies on some of these flags from,
-# e.g. base, so they need to be global.
+# e.g. base, so they need to be global to match the GYP configuration. Also,
+# anything that needs a grit define must be in either this file or features.gni.
 #
-# See also build/config/features.gni
+# PLEASE TRY TO AVOID ADDING FLAGS TO THIS FILE in cases where grit isn't
+# required. See the declare_args block of BUILDCONFIG.gn for advice on how
+# to set up feature flags.
+
+import("//build/config/chromecast_build.gni")
+import("//build/config/headless_build.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
+  use_ash = (is_win || is_linux) && !is_chromecast && !is_headless
 
   # 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
+  # that does not require X11. Enabling this feature disables use of glib, x11,
+  # Pango, and Cairo. Default to false on non-Chromecast builds.
+  use_ozone = (is_chromecast || is_headless) && !is_android
 
   # 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
+  use_aura = is_win || is_linux || is_chromecast
 
   # True means the UI is built using the "views" framework.
-  toolkit_views = is_mac || is_win || is_chromeos || use_aura
+  toolkit_views =
+      (is_mac || is_win || is_chromeos || use_aura) && !is_chromecast
 
   # Whether the entire browser uses toolkit-views on Mac instead of Cocoa.
   mac_views_browser = false
 
+  # Whether we should use GTKv3 instead of GTKv2.
+  use_gtk3 = false
+
+  # Optional system libraries.
+  use_xkbcommon = false
+
   # Whether we should use glib, a low level C utility library.
-  use_glib = is_linux && !use_ozone
+  use_glib = is_linux
+
+  # Indicates if Wayland display server support is enabled.
+  enable_wayland_server = is_chromeos
 }
 
 # Additional dependent variables -----------------------------------------------
 #
 # These variables depend on other variables and can't be set externally.
 
-if (is_linux && use_glib) {
+# 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_android
+
+# Indicates if the UI toolkit depends on X11.
+use_x11 = is_linux && !use_ozone
+
+# Turn off glib if Ozone is enabled.
+if (use_ozone) {
+  use_glib = false
+}
+
+if (is_linux && !use_ozone) {
   use_cairo = true
   use_pango = true
 } else {
@@ -49,17 +77,11 @@
   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
+# Whether to use atk, the Accessibility ToolKit library
+use_atk = is_desktop_linux && use_x11
 
 use_clipboard_aurax11 = is_linux && use_aura && use_x11
 
-enable_hidpi = is_mac || is_chromeos || is_win || is_linux
+enable_hidpi = is_mac || is_win || is_linux
+
+enable_topchrome_md = is_chromeos || is_win || is_linux
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 8b0910f..254000b 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -2,14 +2,102 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/compiler/compiler.gni")
+import("//build/config/sanitizers/sanitizers.gni")
 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.
+assert(is_win)
 
+# This is included by reference in the //build/config/compiler config that
+# is applied to all targets. It is here to separate out the logic that is
+# Windows-only.
+config("compiler") {
+  if (current_cpu == "x86") {
+    asmflags = [
+      # When /safeseh is specified, the linker will only produce an image if it
+      # can also produce a table of the image's safe exception handlers. This
+      # table specifies for the operating system which exception handlers are
+      # valid for the image. Note that /SAFESEH isn't accepted on the command
+      # line, only /safeseh. This is only accepted by ml.exe, not ml64.exe.
+      "/safeseh",
+    ]
+  }
+
+  cflags = [
+    "/Gy",  # Enable function-level linking.
+    "/GS",  # Enable buffer security checking.
+    "/FS",  # Preserve previous PDB behavior.
+    "/bigobj",  # Some of our files are bigger than the regular limits.
+  ]
+
+  # Force C/C++ mode for the given GN detected file type. This is necessary
+  # for precompiled headers where the same source file is compiled in both
+  # modes.
+  cflags_c = [ "/TC" ]
+  cflags_cc = [ "/TP" ]
+
+  # Work around crbug.com/526851, bug in VS 2015 RTM compiler.
+  if (visual_studio_version == "2015") {
+    cflags += [ "/Zc:sizedDealloc-" ]
+  }
+
+  # Building with Clang on Windows is a work in progress and very
+  # experimental. See crbug.com/82385.
+  # Keep this in sync with the similar block in build/common.gypi
+  if (is_clang) {
+    cflags += [
+      # Many files use intrinsics without including this header.
+      # TODO(hans): Fix those files, or move this to sub-GYPs.
+      "/FIIntrin.h",
+    ]
+
+    if (visual_studio_version == "2013") {
+      cflags += [ "-fmsc-version=1800" ]
+    } else if (visual_studio_version == "2015") {
+      cflags += [ "-fmsc-version=1900" ]
+    }
+
+    if (current_cpu == "x86") {
+      cflags += [ "-m32" ]
+    } else {
+      cflags += [ "-m64" ]
+    }
+
+    if (exec_script("//build/win/use_ansi_codes.py", [], "trim string") ==
+        "True") {
+      cflags += [
+        # cmd.exe doesn't understand ANSI escape codes by default,
+        # so only enable them if something emulating them is around.
+        "-fansi-escape-codes",
+      ]
+    }
+  }
+
+  if (is_syzyasan) {
+    # SyzyAsan needs /PROFILE turned on to produce appropriate pdbs.
+    assert(!is_win_fastlink, "/PROFILE and /DEBUG:FASTLINK are incompatible")
+    ldflags = [ "/PROFILE" ]
+  }
+}
+
+# This is included by reference in the //build/config/compiler:runtime_library
+# config that is applied to all targets. It is here to separate out the logic
+# that is Windows-only. Please see that target for advice on what should go in
+# :runtime_library vs. :compiler.
+config("runtime_library") {
+  cflags = []
+
+  # Defines that set up the CRT.
   defines = [
+    "__STD_C",
+    "_CRT_RAND_S",
+    "_CRT_SECURE_NO_DEPRECATE",
+    "_HAS_EXCEPTIONS=0",
+    "_SCL_SECURE_NO_DEPRECATE",
+  ]
+
+  # Defines that set up the Windows SDK.
+  defines += [
     "_ATL_NO_OPENGL",
     "_WINDOWS",
     "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
@@ -21,6 +109,33 @@
     # This is required for ATL to use XP-safe versions of its functions.
     "_USING_V110_SDK71_",
   ]
+
+  if (is_component_build) {
+    # Component mode: dynamic CRT. 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 {
+    if (current_os != "win") {
+      # WindowsRT: use the dynamic CRT.
+      if (is_debug) {
+        cflags += [ "/MDd" ]
+      } else {
+        cflags += [ "/MD" ]
+      }
+    } else {
+      # Desktop Windows: static CRT.
+      if (is_debug) {
+        cflags += [ "/MTd" ]
+      } else {
+        cflags += [ "/MT" ]
+      }
+    }
+  }
 }
 
 # Sets the default Windows build version. This is separated because some
@@ -51,7 +166,7 @@
       "$visual_studio_path\VC\lib",
       "$visual_studio_path\VC\atlmfc\lib",
     ]
-    if (!is_asan) {
+    if (!is_syzyasan) {
       ldflags += [ "/largeaddressaware" ]
     }
   }
@@ -103,8 +218,8 @@
   # 5.02 = Windows Server 2003.
   subsystem_version_suffix = ",5.02"
 } else {
-  # Don't specify a min version on x86.
-  subsystem_version_suffix = ""
+  # 5.01 = Windows XP.
+  subsystem_version_suffix = ",5.01"
 }
 
 config("console") {
@@ -179,3 +294,28 @@
 config("nominmax") {
   defines = [ "NOMINMAX" ]
 }
+
+# Target WinRT ----------------------------------------------------------------
+
+# When targeting Windows Runtime, certain compiler/linker flags are necessary.
+
+config("target_winrt") {
+  defines = [
+    "WINRT",
+    "WINAPI_FAMILY=WINAPI_FAMILY_PC_APP",
+  ]
+  cflags_cc = [
+    "/ZW",
+    "/EHsc",
+  ]
+}
+
+# Internal stuff --------------------------------------------------------------
+
+# Config used by the MIDL template to disable warnings.
+config("midl_warnings") {
+  if (is_clang) {
+    # MIDL generates code like "#endif !_MIDL_USE_GUIDDEF_".
+    cflags = [ "-Wno-extra-tokens" ]
+  }
+}
diff --git a/build/config/win/manifest.gni b/build/config/win/manifest.gni
new file mode 100644
index 0000000..285cf25
--- /dev/null
+++ b/build/config/win/manifest.gni
@@ -0,0 +1,182 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# HOW MANIFESTS WORK IN THE GN BUILD
+#
+# Use the windows_manifest template to declare a manifest generation step.
+# This will combine all listed .manifest files and generate a resource file
+# referencing the resulting manifest. To link this manifest, just depend on
+# the manifest target from your executable or shared library.
+#
+# This will define an empty placeholder target on non-Windows platforms so
+# the manifest declarations and dependencies do not need to be inside of OS
+# conditionals.
+#
+# Manifests uses different resource IDs for EXE and DLL targets. You will need
+# to specify this in the manifest target declaration and only use that manifest
+# target from the correct type of binary target.
+#
+# A binary can depend on only one manifest target, but the manifest target
+# can depend on many individual .manifest files which will be merged. As a
+# result, only executables and shared libraries should depend on manifest
+# targets. If you want to add a manifest to a component, put the dependency
+# behind a "if (is_component_build)" conditional.
+#
+# Generally you will just want the defaults for the Chrome build. In this case
+# the binary should just depend on one of the targets in //build/win/. There
+# are also individual manifest files in that directory you can reference via
+# the *_manifest variables defined below to pick and choose only some defaults.
+# You might combine these with a custom manifest file to get specific behavior.
+
+# Reference this manifest as a source from windows_manifest targets to get
+# the default Chrome OS compatibility list.
+default_compatibility_manifest = "//build/win/compatibility.manifest"
+
+# Reference this manifest as a source from windows_manifest targets to get
+# the default Chrome common constrols compatibility.
+common_controls_manifest = "//build/win/common_controls.manifest"
+
+# Reference this manifest to request that Windows not perform any elevation
+# when running your program. Otherwise, it might do some autodetection and
+# request elevated privileges from the user. This is normally what you want.
+as_invoker_manifest = "//build/win/as_invoker.manifest"
+
+# An alternative to as_invoker_manifest when you want the application to always
+# elevate.
+require_administrator_manifest = "//build/win/require_administrator.manifest"
+
+# Construct a target to combine the given manifest files into a .rc file.
+#
+# Variables for the windows_manifest template:
+#
+#   sources: (required)
+#     List of source .manifest files to add.
+#
+#   type: "dll" or "exe" (required)
+#     Indicates the type of target that this manifest will be used for.
+#     DLLs and EXEs have different manifest resource IDs.
+#
+#   deps: (optional)
+#   visibility: (optional)
+#     Normal meaning.
+#
+# Example:
+#
+#   windows_manifest("doom_melon_manifest") {
+#     sources = [
+#       "doom_melon.manifest",   # Custom values in here.
+#       default_compatibility_manifest,  # Want the normal OS compat list.
+#     ]
+#     type = "exe"
+#   }
+#
+#   executable("doom_melon") {
+#     deps = [ ":doom_melon_manifest" ]
+#     ...
+#   }
+
+if (is_win) {
+  # This is the environment file that gyp-win-tool will use for the current
+  # toolchain. It is placed in root_build_dir by the toolchain setup. This
+  # variable is the path relative to the root_build_dir which is what
+  # gyp-win-tool expects as an argument.
+  _environment_file = "environment.$current_cpu"
+
+  template("windows_manifest") {
+    manifest_action_name = "${target_name}__gen_manifest"
+    rc_action_name = "${target_name}__gen_rc"
+    source_set_name = target_name
+
+    output_manifest = "$target_gen_dir/$source_set_name.manifest"
+    rcfile = "$output_manifest.rc"
+
+    # Make the final .manifest file.
+    action(manifest_action_name) {
+      visibility = [ ":$source_set_name" ]
+
+      script = "$root_build_dir/gyp-win-tool"
+
+      assert(defined(invoker.sources),
+             "\"sources\" must be defined for a windows_manifest target")
+      inputs = invoker.sources
+
+      outputs = [
+        output_manifest,
+      ]
+
+      args = [
+        "manifest-wrapper",
+        _environment_file,
+        "mt.exe",
+        "-nologo",
+        "-manifest",
+      ]
+      args += rebase_path(invoker.sources, root_build_dir)
+      args += [ "-out:" + rebase_path(output_manifest, root_build_dir) ]
+
+      # Apply any dependencies from the invoker to this target, since those
+      # dependencies may have created the input manifest files.
+      forward_variables_from(invoker, [ "deps" ])
+    }
+
+    # Make the .rc file that references the final manifest file. The manifest
+    # generation doesn't need to be a dependency because it's not actually
+    # needed until the .rc is compiled.
+    #
+    # This could easily be combined into one step, but this current separation
+    # of .manifest and .rc matches GYP and allows us to re-use gyp-win-tool.
+    action(rc_action_name) {
+      visibility = [ ":$source_set_name" ]
+
+      script = "$root_build_dir/gyp-win-tool"
+
+      outputs = [
+        rcfile,
+      ]
+
+      # EXEs have a resource ID of 1 for their manifest, DLLs use 2.
+      assert(defined(invoker.type),
+             "\"type\" must be defined for a windows_manifest")
+      if (invoker.type == "exe") {
+        manifest_resource_id = "1"
+      } else if (invoker.type == "dll") {
+        manifest_resource_id = "2"
+      } else {
+        assert(false, "Bad value of \"type\", Must be \"exe\" or \"dll\"")
+      }
+
+      args = [
+        "manifest-to-rc",
+        "$_environment_file",
+        rebase_path(output_manifest),
+        rebase_path(rcfile, root_build_dir),
+        manifest_resource_id,
+      ]
+    }
+
+    # This source set only exists to compile and link the resource file.
+    source_set(source_set_name) {
+      forward_variables_from(invoker, [ "visibility" ])
+      sources = [
+        rcfile,
+      ]
+      deps = [
+        ":$manifest_action_name",
+        ":$rc_action_name",
+      ]
+    }
+  }
+} else {
+  # Make a no-op group on non-Windows platforms so windows_manifest
+  # instantiations don't need to be inside windows blocks.
+  template("windows_manifest") {
+    group(target_name) {
+      # Prevent unused variable warnings on non-Windows platforms.
+      assert(invoker.type == "exe" || invoker.type == "dll")
+      assert(invoker.sources != "")
+      assert(!defined(invoker.deps) || invoker.deps != "")
+      assert(!defined(invoker.visibility) || invoker.visibility != "")
+    }
+  }
+}
diff --git a/build/config/win/msvs_dependencies.isolate b/build/config/win/msvs_dependencies.isolate
new file mode 100644
index 0000000..6814b43
--- /dev/null
+++ b/build/config/win/msvs_dependencies.isolate
@@ -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.
+{
+  'conditions': [
+    # Copy the VS runtime DLLs into the isolate so that they
+    # don't have to be preinstalled on the target machine.
+    #
+    # VS2013 runtimes
+    ['OS=="win" and msvs_version==2013 and component=="shared_library" and CONFIGURATION_NAME=="Debug"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/x64/msvcp120d.dll',
+          '<(PRODUCT_DIR)/x64/msvcr120d.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and msvs_version==2013 and component=="shared_library" and CONFIGURATION_NAME=="Release"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/x64/msvcp120.dll',
+          '<(PRODUCT_DIR)/x64/msvcr120.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and msvs_version==2013 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 msvs_version==2013 and component=="shared_library" and (CONFIGURATION_NAME=="Release" or CONFIGURATION_NAME=="Release_x64")', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/msvcp120.dll',
+          '<(PRODUCT_DIR)/msvcr120.dll',
+        ],
+      },
+    }],
+    # VS2015 runtimes
+    ['OS=="win" and msvs_version==2015 and component=="shared_library" and CONFIGURATION_NAME=="Debug"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/x64/msvcp140d.dll',
+          '<(PRODUCT_DIR)/x64/vccorlib140d.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and msvs_version==2015 and component=="shared_library" and CONFIGURATION_NAME=="Release"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/x64/msvcp140.dll',
+          '<(PRODUCT_DIR)/x64/vccorlib140.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and msvs_version==2015 and component=="shared_library" and (CONFIGURATION_NAME=="Debug" or CONFIGURATION_NAME=="Debug_x64")', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/msvcp140d.dll',
+          '<(PRODUCT_DIR)/vccorlib140d.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and msvs_version==2015 and component=="shared_library" and (CONFIGURATION_NAME=="Release" or CONFIGURATION_NAME=="Release_x64")', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/msvcp140.dll',
+          '<(PRODUCT_DIR)/vccorlib140.dll',
+        ],
+      },
+    }],
+  ],
+}
diff --git a/build/config/win/visual_studio_version.gni b/build/config/win/visual_studio_version.gni
index 6a2828c..358fdb3 100644
--- a/build/config/win/visual_studio_version.gni
+++ b/build/config/win/visual_studio_version.gni
@@ -20,6 +20,8 @@
   # 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"
+
+  is_win_fastlink = false
 }
 
 if (visual_studio_path == "") {
diff --git a/build/config/zip.gni b/build/config/zip.gni
new file mode 100644
index 0000000..dd5cb01
--- /dev/null
+++ b/build/config/zip.gni
@@ -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.
+
+# 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),
+      ]
+    }
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+    if (defined(invoker.public_deps)) {
+      public_deps = invoker.public_deps
+    }
+    if (defined(invoker.data_deps)) {
+      data_deps = invoker.data_deps
+    }
+
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+  }
+}
diff --git a/build/copy_test_data_ios.gypi b/build/copy_test_data_ios.gypi
index 576a0f2..56a222f 100644
--- a/build/copy_test_data_ios.gypi
+++ b/build/copy_test_data_ios.gypi
@@ -34,12 +34,7 @@
 
 {
   '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))',
+    '<!@pymod_do_main(copy_test_data_ios --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))',
diff --git a/build/download_gold_plugin.py b/build/download_gold_plugin.py
index cd7ca41..d4fb48b 100755
--- a/build/download_gold_plugin.py
+++ b/build/download_gold_plugin.py
@@ -5,6 +5,7 @@
 
 """Script to download LLVM gold plugin from google storage."""
 
+import find_depot_tools
 import json
 import os
 import shutil
@@ -14,9 +15,7 @@
 
 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')
@@ -35,8 +34,13 @@
 
   os.chdir(LLVM_BUILD_PATH)
 
+  # TODO(pcc): Fix gsutil.py cp url file < /dev/null 2>&0
+  # (currently aborts with exit code 1,
+  # https://github.com/GoogleCloudPlatform/gsutil/issues/289) or change the
+  # stdin->stderr redirect in update.py to do something else (crbug.com/494442).
   subprocess.check_call(['python', GSUTIL_PATH,
-                         'cp', remote_path, targz_name])
+                         'cp', remote_path, targz_name],
+                        stderr=open('/dev/null', 'w'))
   subprocess.check_call(['tar', 'xzf', targz_name])
   os.remove(targz_name)
   return 0
diff --git a/build/download_nacl_toolchains.py b/build/download_nacl_toolchains.py
index b99b940..cccecce 100755
--- a/build/download_nacl_toolchains.py
+++ b/build/download_nacl_toolchains.py
@@ -14,6 +14,8 @@
   # Exit early if disable_nacl=1.
   if 'disable_nacl=1' in os.environ.get('GYP_DEFINES', ''):
     return 0
+  if 'OS=android' 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')
diff --git a/build/download_sdk_extras.py b/build/download_sdk_extras.py
deleted file mode 100755
index d7c5d6c..0000000
--- a/build/download_sdk_extras.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/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/filename_rules.gypi b/build/filename_rules.gypi
index 48c8027..bc81752 100644
--- a/build/filename_rules.gypi
+++ b/build/filename_rules.gypi
@@ -9,16 +9,16 @@
 {
   'target_conditions': [
     ['OS!="win" or >(nacl_untrusted_build)==1', {
-      'sources/': [ ['exclude', '_win(_browsertest|_unittest)?\\.(h|cc)$'],
+      'sources/': [ ['exclude', '_win(_browsertest|_unittest|_test)?\\.(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)/'] ],
+      'sources/': [ ['exclude', '_(cocoa|mac|mach)(_unittest|_test)?\\.(h|cc|c|mm?)$'],
+                    ['exclude', '(^|/)(cocoa|mac|mach)/'] ],
     }],
     ['OS!="ios" or >(nacl_untrusted_build)==1', {
-      'sources/': [ ['exclude', '_ios(_unittest)?\\.(h|cc|mm?)$'],
+      'sources/': [ ['exclude', '_ios(_unittest|_test)?\\.(h|cc|mm?)$'],
                     ['exclude', '(^|/)ios/'] ],
     }],
     ['(OS!="mac" and OS!="ios") or >(nacl_untrusted_build)==1', {
@@ -31,25 +31,25 @@
     # 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(_unittest|_test)?\\.(h|cc)$'],
         ['exclude', '(^|/)linux/'],
       ],
     }],
     ['OS!="android" or _toolset=="host" or >(nacl_untrusted_build)==1', {
       'sources/': [
-        ['exclude', '_android(_unittest)?\\.(h|cc)$'],
+        ['exclude', '_android(_unittest|_test)?\\.(h|cc)$'],
         ['exclude', '(^|/)android/'],
       ],
     }],
     ['OS=="win" and >(nacl_untrusted_build)==0', {
       'sources/': [
-        ['exclude', '_posix(_unittest)?\\.(h|cc)$'],
+        ['exclude', '_posix(_unittest|_test)?\\.(h|cc)$'],
         ['exclude', '(^|/)posix/'],
       ],
     }],
     ['<(chromeos)!=1 or >(nacl_untrusted_build)==1', {
       'sources/': [
-        ['exclude', '_chromeos(_unittest)?\\.(h|cc)$'],
+        ['exclude', '_chromeos(_unittest|_test)?\\.(h|cc)$'],
         ['exclude', '(^|/)chromeos/'],
       ],
     }],
@@ -97,14 +97,7 @@
       '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/'],
-      ]
+      'sources/': [ ['exclude', '_ozone(_browsertest|_unittest)?\\.(h|cc)$'] ]
     }],
     ['<(use_pango)==0', {
       'sources/': [ ['exclude', '(^|_)pango(_util|_browsertest|_unittest)?\\.(h|cc)$'], ],
diff --git a/build/find_depot_tools.py b/build/find_depot_tools.py
new file mode 100755
index 0000000..1c34fea
--- /dev/null
+++ b/build/find_depot_tools.py
@@ -0,0 +1,60 @@
+#!/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.
+"""Small utility function to find depot_tools and add it to the python path.
+
+Will throw an ImportError exception if depot_tools can't be found since it
+imports breakpad.
+
+This can also be used as a standalone script to print out the depot_tools
+directory location.
+"""
+
+import os
+import sys
+
+
+def IsRealDepotTools(path):
+  return os.path.isfile(os.path.join(path, 'gclient.py'))
+
+
+def add_depot_tools_to_path():
+  """Search for depot_tools and add it to sys.path."""
+  # First look if depot_tools is already in PYTHONPATH.
+  for i in sys.path:
+    if i.rstrip(os.sep).endswith('depot_tools') and IsRealDepotTools(i):
+      return i
+  # Then look if depot_tools is in PATH, common case.
+  for i in os.environ['PATH'].split(os.pathsep):
+    if IsRealDepotTools(i):
+      sys.path.append(i.rstrip(os.sep))
+      return i
+  # Rare case, it's not even in PATH, look upward up to root.
+  root_dir = os.path.dirname(os.path.abspath(__file__))
+  previous_dir = os.path.abspath(__file__)
+  while root_dir and root_dir != previous_dir:
+    i = os.path.join(root_dir, 'depot_tools')
+    if IsRealDepotTools(i):
+      sys.path.append(i)
+      return i
+    previous_dir = root_dir
+    root_dir = os.path.dirname(root_dir)
+  print >> sys.stderr, 'Failed to find depot_tools'
+  return None
+
+DEPOT_TOOLS_PATH = add_depot_tools_to_path()
+
+# pylint: disable=W0611
+import breakpad
+
+
+def main():
+  if DEPOT_TOOLS_PATH is None:
+    return 1
+  print DEPOT_TOOLS_PATH
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/gdb-add-index b/build/gdb-add-index
index 992ac16..8df437f 100755
--- a/build/gdb-add-index
+++ b/build/gdb-add-index
@@ -13,6 +13,17 @@
 # When modifying this code, most of the real logic is in the index_one_file
 # function. The rest is cleanup + sempahore plumbing.
 
+function usage_exit {
+  echo "Usage: $0 [-f] [-r] [-n] <paths-to-binaries>..."
+  echo "  -f forces replacement of an existing index."
+  echo "  -r removes the index section."
+  echo "  -n don't extract the dependencies of each binary with lld."
+  echo "       e.g., $0 -n out/Debug/lib.unstripped/lib*"
+  echo
+  echo "  Set TOOLCHAIN_PREFIX to use a non-default set of binutils."
+  exit 1
+}
+
 # Cleanup temp directory and ensure all child jobs are dead-dead.
 function on_exit {
   trap "" EXIT USR1  # Avoid reentrancy.
@@ -25,9 +36,9 @@
     echo "done"
   fi
 
-  if [ -f "$DIRECTORY" ]; then
-    echo -n "Removing temp directory $DIRECTORY..."
-    rm -rf $DIRECTORY
+  if [ -f "$directory" ]; then
+    echo -n "Removing temp directory $directory..."
+    rm -rf "$directory"
     echo done
   fi
 }
@@ -36,31 +47,31 @@
 function index_one_file {
   local file=$1
   local basename=$(basename "$file")
-  local should_index="${SHOULD_INDEX}"
+  local should_index_this_file="${should_index}"
 
   local readelf_out=$(${TOOLCHAIN_PREFIX}readelf -S "$file")
   if [[ $readelf_out =~ "gdb_index" ]]; then
-    if [ "${REMOVE_INDEX}" = 1 ]; then
+    if $remove_index; then
       ${TOOLCHAIN_PREFIX}objcopy --remove-section .gdb_index "$file"
       echo "Removed index from $basename."
     else
       echo "Skipped $basename -- already contains index."
-      should_index=0
+      should_index_this_file=false
     fi
   fi
 
-  if [ "${should_index}" = 1 ]; then
+  if $should_index_this_file; then
     local start=$(date +"%s%N")
     echo "Adding index to $basename..."
 
-    ${TOOLCHAIN_PREFIX}gdb -batch "$file" -ex "save gdb-index $DIRECTORY" \
+    ${TOOLCHAIN_PREFIX}gdb -batch "$file" -ex "save gdb-index $directory" \
       -ex "quit"
-    local index_file="$DIRECTORY/$basename.gdb-index"
+    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))
+      local elapsed=$(((finish - start) / 1000000))
       echo "   ...$basename indexed. [${elapsed}ms]"
     else
       echo "   ...$basename unindexable."
@@ -79,75 +90,86 @@
   } &
 }
 
-CUR_FILE_NUM=0
+cur_file_num=0
 function index_next {
-  if (( CUR_FILE_NUM >= ${#FILES_TO_INDEX[@]} )); then
+  if ((cur_file_num >= ${#files_to_index[@]})); then
     return
   fi
 
-  async_index "${FILES_TO_INDEX[CUR_FILE_NUM]}"
-  ((CUR_FILE_NUM += 1)) || true
+  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
+remove_index=false
+should_index=true
+should_index_deps=true
+files_to_index=()
+while (($# > 0)); do
+  case "$1" in
+    -h)
+      usage_exit
       ;;
-    r)
-      REMOVE_INDEX=1
-      SHOULD_INDEX=0
-      shift
+    -f)
+      remove_index=true
+      ;;
+    -r)
+      remove_index=true
+      should_index=false
+      ;;
+    -n)
+      should_index_deps=false
+      ;;
+    -*)
+      echo "Invalid option: $1" >&2
+      usage_exit
       ;;
     *)
-      echo "Invalid option: -$OPTARG" >&2
+      if [[ ! -f "$1" ]]; then
+        echo "Path $1 does not exist."
+        exit 1
+      fi
+      files_to_index+=("$1")
       ;;
   esac
+  shift
 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
+if ((${#files_to_index[@]} == 0)); then
+  usage_exit
 fi
 
-FILENAME="$1"
-if [[ ! -f "$FILENAME" ]]; then
-  echo "Path $FILENAME does not exist."
-  exit 1
+dependencies=()
+if $should_index_deps; then
+  for file in "${files_to_index[@]}"; do
+      # Append the shared library dependencies of this file that
+      # have the same dirname. The dirname is a signal that these
+      # shared libraries were part of the same build as the binary.
+      dependencies+=( \
+        $(ldd "$file" 2>/dev/null \
+          | grep $(dirname "$file") \
+          | sed "s/.*[ \t]\(.*\) (.*/\1/") \
+      )
+  done
 fi
+files_to_index+=("${dependencies[@]}")
 
 # Ensure we cleanup on on exit.
-trap on_exit EXIT
+trap on_exit EXIT INT
 
 # 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/")
-)
+directory=$(mktemp -d)
+echo "Made temp directory $directory."
 
 # 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_tasks=${INDEX_TASKS:-4}
+for ((i = 0; i < index_tasks; i++)); do
   index_next
 done
 
@@ -157,6 +179,6 @@
 # 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
+while (($? > 128)); do
   wait
 done
diff --git a/build/get_landmines.py b/build/get_landmines.py
index 71345bb..4139957 100755
--- a/build/get_landmines.py
+++ b/build/get_landmines.py
@@ -55,6 +55,8 @@
     print "Switched win from VS2010 to VS2013."
     print "Update to VS2013 Update 2."
     print "Update to VS2013 Update 4."
+  if (platform() == 'win' and gyp_msvs_version().startswith('2015')):
+    print 'Switch to VS2015'
   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'):
@@ -71,6 +73,12 @@
   print 'Remove NaCl toolchains from the output dir (crbug.com/456902)'
   if platform() == 'ios':
     print 'Clobber iOS to workaround Xcode deps bug (crbug.com/485435)'
+  if platform() == 'win':
+    print 'Clobber to delete stale generated files (crbug.com/510086)'
+  if platform() == 'android' and gyp_defines().get('target_arch') == 'arm64':
+    print 'Clobber to support new location/infra for chrome_sync_shell_apk'
+  if platform() == 'mac':
+    print 'Clobber to get rid of evil libsqlite3.dylib (crbug.com/526208)'
 
 
 def main():
diff --git a/build/get_sdk_extras_packages.py b/build/get_sdk_extras_packages.py
deleted file mode 100755
index 6d870cc..0000000
--- a/build/get_sdk_extras_packages.py
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/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
index 2577c7c..1cab3fc 100755
--- a/build/get_syzygy_binaries.py
+++ b/build/get_syzygy_binaries.py
@@ -5,7 +5,6 @@
 
 """A utility script for downloading versioned Syzygy binaries."""
 
-import cStringIO
 import hashlib
 import errno
 import json
@@ -17,15 +16,15 @@
 import stat
 import sys
 import subprocess
-import urllib2
+import tempfile
+import time
 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')
+# The relative path where official builds are archived in their GS bucket.
+_SYZYGY_ARCHIVE_PATH = ('/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
@@ -49,17 +48,6 @@
       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.
@@ -248,12 +236,50 @@
   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 _FindGsUtil():
+  """Looks for depot_tools and returns the absolute path to gsutil.py."""
+  for path in os.environ['PATH'].split(os.pathsep):
+    path = os.path.abspath(path)
+    git_cl = os.path.join(path, 'git_cl.py')
+    gs_util = os.path.join(path, 'gsutil.py')
+    if os.path.exists(git_cl) and os.path.exists(gs_util):
+      return gs_util
+  return None
+
+
+def _GsUtil(*cmd):
+  """Runs the given command in gsutil with exponential backoff and retries."""
+  gs_util = _FindGsUtil()
+  cmd = [sys.executable, gs_util] + list(cmd)
+
+  retries = 3
+  timeout = 4  # Seconds.
+  while True:
+    _LOGGER.debug('Running %s', cmd)
+    prog = subprocess.Popen(cmd, shell=False)
+    prog.communicate()
+
+    # Stop retrying on success.
+    if prog.returncode == 0:
+      return
+
+    # Raise a permanent failure if retries have been exhausted.
+    if retries == 0:
+      raise RuntimeError('Command "%s" returned %d.' % (cmd, prog.returncode))
+
+    _LOGGER.debug('Sleeping %d seconds and trying again.', timeout)
+    time.sleep(timeout)
+    retries -= 1
+    timeout *= 2
+
+
+def _Download(resource):
+  """Downloads the given GS resource to a temporary file, returning its path."""
+  tmp = tempfile.mkstemp(suffix='syzygy_archive')
+  os.close(tmp[0])
+  url = 'gs://syzygy-archive' + resource
+  _GsUtil('cp', url, tmp[1])
+  return tmp[1]
 
 
 def _InstallBinaries(options, deleted={}):
@@ -261,7 +287,7 @@
   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 }
+  archive_path = _SYZYGY_ARCHIVE_PATH % { 'revision': options.revision }
   if options.resources:
     resources = [(resource, resource, '', None)
                  for resource in options.resources]
@@ -278,33 +304,37 @@
       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)
+    # Download and read the archive.
+    resource = archive_path + '/' + base
+    _LOGGER.debug('Retrieving %s archive at "%s".', name, resource)
+    path = _Download(resource)
 
     _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)
+    with open(path, 'rb') as data:
+      archive = zipfile.ZipFile(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)
+          # 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)
+
+    _LOGGER.debug('Removing temporary file "%s".', path)
+    os.remove(path)
 
   return state
 
@@ -316,6 +346,9 @@
       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('--no-cleanup', action='store_true', default=False,
+      help='Allow installation on non-Windows platforms, and skip the forced '
+           'cleanup step.')
   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.')
@@ -408,7 +441,10 @@
   # 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)
+    if options.no_cleanup:
+      _LOGGER.debug('Skipping usual cleanup for non-Windows platforms.')
+    else:
+      return _RemoveOrphanedFiles(options)
 
   # Load the current installation state, and validate it against the
   # requested installation.
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index ab16c05..dc2a6c5 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -12,9 +12,6 @@
 # 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.
 #
@@ -22,13 +19,15 @@
 # above contracts.
 
 {
+  'includes': [
+    '../media/media_variables.gypi'
+  ],
   'targets': [
     {
       'target_name': 'gyp_all',
       'type': 'none',
       'dependencies': [
         'both_gn_and_gyp',
-        'gyp_only',
         'gyp_remaining',
       ]
     },
@@ -41,28 +40,14 @@
         '../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',
@@ -72,144 +57,46 @@
         '../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/cast/cast.gyp:cast_unittests',
         '../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',
+        '../mojo/mojo_base.gyp:mojo_application_base',
         '../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/Source/platform/blink_platform_tests.gyp:blink_heap_unittests',
         '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests',
         '../third_party/WebKit/Source/web/web_tests.gyp:webkit_unit_tests',
         '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests',
-        '../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/battor_agent/battor_agent.gyp:battor_agent',
         '../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/events/events_unittests.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',
@@ -225,7 +112,7 @@
             '../components/nacl.gyp:nacl_loader_unittests',
           ]
         }],
-        ['enable_extensions==1 and OS!="mac"', {
+        ['enable_extensions==1', {
           'dependencies': [
             '../extensions/shell/app_shell.gyp:app_shell',
             '../extensions/shell/app_shell.gyp:app_shell_unittests',
@@ -241,7 +128,7 @@
             '../remoting/remoting_all.gyp:remoting_all',
           ],
         }],
-        ['remoting==1 and chromeos==0', {
+        ['remoting==1 and chromeos==0 and use_x11==1', {
           'dependencies': [
             '../remoting/remoting.gyp:remoting_me2me_host',
             '../remoting/remoting.gyp:remoting_me2me_native_messaging_host',
@@ -255,8 +142,7 @@
         }],
         ['use_ash==1', {
           'dependencies': [
-            '../ash/ash.gyp:ash_shell',
-            '../ash/ash.gyp:ash_shell_unittests',
+            '../ash/ash.gyp:ash_shell_with_content',
             '../ash/ash.gyp:ash_unittests',
           ],
         }],
@@ -293,14 +179,50 @@
         }],
         ['OS=="android"', {
           'dependencies': [
+            '../base/base.gyp:base_junit_tests',
+            '../base/base.gyp:base_unittests_apk',
             '../base/base.gyp:chromium_android_linker',
-            '../breakpad/breakpad.gyp:dump_syms',
+            '../breakpad/breakpad.gyp:breakpad_unittests_deps',
+            '../breakpad/breakpad.gyp:symupload#host',
+            '../breakpad/breakpad.gyp:microdump_stackwalk#host',
+            '../breakpad/breakpad.gyp:minidump_dump#host',
+            '../breakpad/breakpad.gyp:minidump_stackwalk#host',
             '../build/android/rezip.gyp:rezip_apk_jar',
-            '../chrome/chrome.gyp:chrome_shell_apk',
-            '../chrome/chrome.gyp:chromedriver_webview_shell_apk',
+            '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests_apk',
+            '../cc/cc_tests.gyp:cc_unittests_apk',
             #"//clank" TODO(GYP) - conditional somehow?
+            '../components/components_tests.gyp:components_browsertests_apk',
+            '../components/components_tests.gyp:components_junit_tests',
+            '../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_junit_tests',
+            '../content/content_shell_and_tests.gyp:content_shell_apk',
+            '../content/content_shell_and_tests.gyp:content_unittests_apk',
+            '../content/content_shell_and_tests.gyp:video_decode_accelerator_unittest_apk',
+            '../device/device_tests.gyp:device_unittests_apk',
+            '../gpu/gpu.gyp:gpu_unittests_apk',
+            '../media/cast/cast.gyp:cast_unittests_apk',
+            '../media/media.gyp:media_unittests_apk',
+            '../media/midi/midi.gyp:midi_unittests_apk',
+            '../net/net.gyp:net_junit_tests',
+            '../net/net.gyp:net_unittests_apk',
+            '../skia/skia_tests.gyp:skia_unittests_apk',
+            '../sql/sql.gyp:sql_unittests_apk',
+            '../sync/sync.gyp:sync_unit_tests_apk',
+            '../testing/android/junit/junit_test.gyp:junit_unit_tests',
+            '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_heap_unittests_apk',
+            '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests_apk',
+            '../third_party/WebKit/Source/web/web_tests.gyp:webkit_unit_tests_apk',
+            '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests_apk',
+            '../tools/android/heap_profiler/heap_profiler.gyp:heap_profiler_unittests_apk',
             '../tools/imagediff/image_diff.gyp:image_diff#host',
             '../tools/telemetry/telemetry.gyp:bitmaptools#host',
+            '../ui/base/ui_base_tests.gyp:ui_base_unittests_apk',
+            '../ui/events/events_unittests.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',
 
             # TODO(GYP): Remove these when the components_unittests work.
             #"//components/history/core/test:test",
@@ -312,12 +234,6 @@
             #"//components/user_manager",
             #"//components/wallpaper",
 
-            '../content/content_shell_and_tests.gyp:content_shell_apk',
-
-            '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_heap_unittests_apk',
-            '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests_apk',
-            '../third_party/WebKit/Source/web/web_tests.gyp:webkit_unit_tests_apk',
-            '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests_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",
@@ -327,7 +243,6 @@
             #"//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?
@@ -336,29 +251,137 @@
             #"//ui/message_center:test_support",
           ],
           'dependencies!': [
-            '../breakpad/breakpad.gyp:symupload',
-            '../chrome/chrome.gyp:browser_tests',
+            # TODO(GYP): All of these targets need to be ported over.
+            '../url/url.gyp:url_unittests',
+          ],
+        }],
+        ['OS=="android" and chromecast==0', {
+          'dependencies': [
+            '../chrome/android/chrome_apk.gyp:chrome_public_apk',
+            '../chrome/android/chrome_apk.gyp:chrome_public_test_apk',
+            '../chrome/chrome.gyp:chromedriver_webview_shell_apk',
+            '../chrome/chrome.gyp:chrome_junit_tests',
+            '../chrome/chrome.gyp:unit_tests_apk',
+            '../third_party/custom_tabs_client/custom_tabs_client.gyp:custom_tabs_client_example_apk',
+          ],
+        }],
+        ['OS!="android"', {
+          'dependencies': [
+            '../base/base.gyp:build_utf8_validator_tables#host',
+            '../chrome/chrome.gyp:chrome_app_unittests',
             '../chrome/chrome.gyp:chromedriver',
-            '../chrome/chrome.gyp:chromedriver_unitests',
+            '../chrome/chrome.gyp:chromedriver_tests',
+            '../chrome/chrome.gyp:chromedriver_unittests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../content/content_shell_and_tests.gyp:content_shell',
+            '../courgette/courgette.gyp:courgette',
+            '../courgette/courgette.gyp:courgette_fuzz',
+            '../courgette/courgette.gyp:courgette_minimal_tool',
+            '../courgette/courgette.gyp:courgette_unittests',
+            '../gin/gin.gyp:gin_unittests',
+            '../gpu/gles2_conform_support/gles2_conform_support.gyp:gles2_conform_support',  # TODO(GYP) crbug.com/471920
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+            '../google_apis/gcm/gcm.gyp:mcs_probe',
+            '../google_apis/google_apis.gyp:google_apis_unittests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../mojo/mojo.gyp:mojo',
+            '../net/net.gyp:crash_cache',
+            '../net/net.gyp:crl_set_dump',
+            '../net/net.gyp:dns_fuzz_stub',
+            '../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_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',
+            '../sync/sync.gyp:run_sync_testserver',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_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',
+            '../tools/imagediff/image_diff.gyp:image_diff',
+            '../ui/app_list/app_list.gyp:app_list_unittests',
+            '../ui/compositor/compositor.gyp:compositor_unittests',
+          ],
+        }],
+        ['OS!="android" and chromecast==0', {
+          'dependencies': [
+            '../chrome/chrome.gyp:browser_tests',
+            '../chrome/chrome.gyp:chrome',
             '../chrome/chrome.gyp:interactive_ui_tests',
             '../chrome/chrome.gyp:performance_browser_tests',
             '../chrome/chrome.gyp:sync_integration_tests',
-            '../chrome/chrome.gyp:unit_tests',
+            '../chrome/chrome.gyp:sync_performance_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",
+            '../gin/gin.gyp:gin_shell',
+            '../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',
+            '../mojo/mojo_base.gyp:mojo_common_unittests',
+            '../ppapi/tools/ppapi_tools.gyp:pepper_hash_for_uma',
+            '../skia/skia.gyp:filter_fuzz_stub',
+            '../skia/skia.gyp:image_operations_bench',
+            '../sync/tools/sync_tools.gyp:sync_client',
+            '../sync/tools/sync_tools.gyp:sync_listen_notifications',
+            '../third_party/codesighs/codesighs.gyp:codesighs',
+            '../third_party/codesighs/codesighs.gyp:maptsvdifftool',
+            '../third_party/pdfium/samples/samples.gyp:pdfium_diff',
             '../third_party/pdfium/samples/samples.gyp:pdfium_test',
+            '../tools/gn/gn.gyp:generate_test_gn_data',
             '../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',
+            '../tools/perf/clear_system_cache/clear_system_cache.gyp:clear_system_cache',
+            '../ui/message_center/message_center.gyp:message_center_unittests',
+            '../ui/views/examples/examples.gyp:views_examples_with_content_exe',
+          ],
+        }],
+        ['media_use_ffmpeg==1', {
+          'dependencies': [
+            '../media/media.gyp:ffmpeg_regression_tests',
           ],
         }],
         ['OS=="android" or OS=="linux"', {
@@ -379,9 +402,17 @@
             '../rlz/rlz.gyp:rlz_unittests',
           ],
         }],
-        ['OS=="android" or OS=="linux" or os_bsd==1', {
+        ['OS=="linux" or OS=="android" or os_bsd==1', {
           'dependencies': [
+            '../breakpad/breakpad.gyp:breakpad_unittests',
             '../breakpad/breakpad.gyp:core-2-minidump',
+            '../breakpad/breakpad.gyp:dump_syms#host',
+            '../breakpad/breakpad.gyp:generate_test_dump',
+            '../breakpad/breakpad.gyp:minidump-2-core',
+          ],
+        }],
+        ['OS=="linux" or os_bsd==1', {
+          'dependencies': [
             '../breakpad/breakpad.gyp:microdump_stackwalk',
             '../breakpad/breakpad.gyp:minidump_dump',
             '../breakpad/breakpad.gyp:minidump_stackwalk',
@@ -391,12 +422,9 @@
         }],
         ['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:cast_testing_tools',
             '../media/cast/cast.gyp:tap_proxy',
             '../net/net.gyp:disk_cache_memory_test',
             '../net/net.gyp:flip_in_mem_edsm_server',
@@ -411,7 +439,6 @@
             '../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',
          ],
         }],
@@ -425,7 +452,7 @@
 
             # TODO(GYP): remove these when the corresponding root targets work.
             #"//cc/blink",
-            #"//components/ui/zoom:ui_zoom",
+            #"//components/ui/zoom",
             #"//content",
             #"//content/test:test_support",
             #"//device/battery",
@@ -444,7 +471,6 @@
             #"//third_party/ots",
             #"//third_party/qcms",
             #"//third_party/smhasher:murmurhash3",
-            #"//third_party/speex",
             #"//third_party/webrtc/system_wrappers",
             #"//ui/native_theme",
             #"//ui/snapshot",
@@ -472,11 +498,21 @@
           'dependencies': [
             '../base/base.gyp:pe_image_test',
             '../chrome/chrome.gyp:crash_service',
+            '../chrome/chrome.gyp:installer_util_unittests',
+            '../chrome/chrome.gyp:setup',
+            '../chrome/chrome.gyp:setup_unittests',
+            '../chrome/installer/mini_installer.gyp:mini_installer',
             '../chrome_elf/chrome_elf.gyp:chrome_elf_unittests',
             '../chrome_elf/chrome_elf.gyp:dll_hash_main',
+            '../cloud_print/service/win/service.gyp:cloud_print_service',
+            '../cloud_print/service/win/service.gyp:cloud_print_service_config',
+            '../cloud_print/service/win/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',
             '../components/components.gyp:wifi_test',
             '../net/net.gyp:quic_client',
             '../net/net.gyp:quic_server',
+            '../rlz/rlz.gyp:rlz',
             '../sandbox/sandbox.gyp:pocdll',
             '../sandbox/sandbox.gyp:sandbox_poc',
             '../sandbox/sandbox.gyp:sbox_integration_tests',
@@ -489,21 +525,11 @@
             '../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.
-              ]
-            }],
+        ['chromecast==1', {
+          'dependencies': [
+            '../chromecast/chromecast.gyp:cast_shell',
           ]
-        }],
+        }]
       ],
     },
     {
@@ -528,30 +554,87 @@
             '../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',
+            '../crypto/crypto.gyp:crypto_unittests_run',
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests_run',
+            '../google_apis/google_apis.gyp:google_apis_unittests_run',
             '../gpu/gpu.gyp:gpu_unittests_run',
+            '../media/blink/media_blink.gyp:media_blink_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',
+            '../printing/printing.gyp:printing_unittests_run',
+            '../remoting/remoting.gyp:remoting_unittests_run',
+            '../skia/skia_tests.gyp:skia_unittests_run',
             '../sql/sql.gyp:sql_unittests_run',
+            '../sync/sync.gyp:sync_unit_tests_run',
+            '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_heap_unittests_run',
+            '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests_run',
+            '../third_party/WebKit/Source/web/web_tests.gyp:webkit_unit_tests_run',
+            '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests_run',
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests_run',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_bindings_unittests_run',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_environment_unittests_run',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_unittests_run',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_utility_unittests_run',
+            '../tools/gn/gn.gyp:gn_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/compositor/compositor.gyp:compositor_unittests_run',
+            '../ui/events/events_unittests.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',
+            '../url/url.gyp:url_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',
+          'conditions': [
+            ['OS=="linux"', {
+              'dependencies': [
+                '../sandbox/sandbox.gyp:sandbox_linux_unittests_run',
+                '../ui/display/display.gyp:display_unittests_run',
+              ],
+            }],
+            ['OS=="mac"', {
+              'dependencies': [
+                '../sandbox/sandbox.gyp:sandbox_mac_unittests_run',
+              ],
+            }],
+            ['OS=="win"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:installer_util_unittests_run',
+                '../chrome/chrome.gyp:setup_unittests_run',
+                '../sandbox/sandbox.gyp:sbox_integration_tests',
+                '../sandbox/sandbox.gyp:sbox_unittests',
+                '../sandbox/sandbox.gyp:sbox_validation_tests',
+              ],
+            }],
+            ['OS!="android"', {
+              'dependencies': [
+                '../ipc/ipc.gyp:ipc_tests_run',
+                '../ui/gl/gl_tests.gyp:gl_unittests_run',
+                '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests_run',
+              ],
+            }],
+            ['use_ash==1', {
+              'dependencies': [
+                '../ash/ash.gyp:ash_unittests_run',
+              ],
+            }],
+            ['use_aura==1', {
+              'dependencies': [
+                '../ui/aura/aura.gyp:aura_unittests_run',
+                '../ui/wm/wm.gyp:wm_unittests_run',
+              ],
+            }],
+            ['enable_webrtc==1 or OS!="android"', {
+              'dependencies': [
+                '../jingle/jingle.gyp:jingle_unittests_run',
+              ],
+            }],
+            ['disable_nacl==0 and disable_nacl_untrusted==0', {
+              'dependencies': [
+                '../components/nacl.gyp:nacl_loader_unittests_run',
+              ]
+            }],
           ],
         }],
         ['use_openssl==1', {
@@ -588,6 +671,7 @@
         }],
         ['chromeos==1', {
           'dependencies': [
+            '../content/content_shell_and_tests.gyp:jpeg_decode_accelerator_unittest',
             '../content/content_shell_and_tests.gyp:video_encode_accelerator_unittest',
           ],
         }],
@@ -605,7 +689,7 @@
           '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',
+            '../remoting/remoting.gyp:ar_sample_test_driver',
 
             # TODO(GYP): in progress - see tfarina.
             '../third_party/webrtc/tools/tools.gyp:frame_analyzer',
@@ -615,37 +699,31 @@
         ['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',
+
+            # This is a safe browsing utility only necessary for developers.
+            # For now, we can skip this and anybody that needs this can add it
+            # to the GN build.
             '../chrome/chrome.gyp:sb_sigutil',
-            '../chrome/chrome.gyp:setup',
-            '../chrome/chrome.gyp:setup_unittests',
-            '../chrome/installer/mini_installer.gyp:mini_installer',
+
+            # This project is up in the air. Don't need to convert it unless
+            # we decide we need for something. Owner: scottmg.
             '../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',
+            '../components/test_runner/test_runner.gyp:layout_test_helper',
             '../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: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',
           ],
         }],
@@ -676,6 +754,46 @@
             '../components/components.gyp:policy_win64',
           ]
         }],
+        ['OS=="android"', {
+          'dependencies': [
+            '../base/base.gyp:base_perftests_apk',
+            '../cc/cc_tests.gyp:cc_perftests_apk',
+            '../components/components.gyp:cronet_sample_apk',
+            '../components/components.gyp:cronet_sample_test_apk',
+            '../components/components.gyp:cronet_test_apk',
+            '../components/components.gyp:cronet_test_instrumentation_apk',
+            '../components/components.gyp:cronet_perf_test_apk',
+            '../content/content_shell_and_tests.gyp:chromium_linker_test_apk',
+            '../content/content_shell_and_tests.gyp:content_shell_test_apk',
+            '../gpu/gpu.gyp:gl_tests_apk',
+            '../gpu/gpu.gyp:gpu_perftests_apk',
+            '../ipc/ipc.gyp:ipc_tests_apk',
+            '../media/media.gyp:media_perftests_apk',
+            '../sandbox/sandbox.gyp:sandbox_linux_unittests_deps',
+            '../tools/android/android_tools.gyp:memconsumer',
+            '../ui/android/ui_android.gyp:ui_android_unittests_apk',
+            '../url/url.gyp:url_unittests',
+          ],
+        }],
+        ['OS=="android" and chromecast==0', {
+          'dependencies': [
+            '../android_webview/android_webview.gyp:android_webview_apk',
+            '../android_webview/android_webview.gyp:android_webview_test_apk',
+            '../android_webview/android_webview.gyp:android_webview_unittests',
+            '../android_webview/android_webview.gyp:android_webview_unittests_apk',
+            '../android_webview/android_webview.gyp:system_webview_apk',
+            '../android_webview/android_webview_shell.gyp:system_webview_shell_apk',
+            '../android_webview/android_webview_shell.gyp:system_webview_shell_layout_test_apk',
+            '../android_webview/android_webview_shell.gyp:system_webview_shell_page_cycler_apk',
+            '../chrome/android/chrome_apk.gyp:chrome_sync_shell_apk',
+            '../chrome/android/chrome_apk.gyp:chrome_sync_shell_test_apk',
+          ],
+        }],
+        ['OS=="android" and target_arch != "x64"', {
+          'dependencies': [
+            '../third_party/android_platform/relocation_packer.gyp:android_relocation_packer_unittests#host'
+          ],
+        }],
       ],
     },
   ]
diff --git a/build/gyp_chromium b/build/gyp_chromium
index 736062e..4fc62ba 100755
--- a/build/gyp_chromium
+++ b/build/gyp_chromium
@@ -1,331 +1,12 @@
 #!/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.
+# Simple launcher script for gyp_chromium.py.
+# TODO(sbc): This should probably be shell script but for historical
+# reasons (all the python code used to live in this script without a
+# .py extension, and was often run as 'python gyp_chromium') it is
+# currently still python.
 
-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)
+execfile(__file__ + '.py')
diff --git a/build/gyp_chromium.py b/build/gyp_chromium.py
index f9e8ac8..15fa3f6 100644
--- a/build/gyp_chromium.py
+++ b/build/gyp_chromium.py
@@ -1,18 +1,336 @@
-# Copyright 2012 The Chromium Authors. All rights reserved.
+# Copyright (c) 2012 The Chromium Authors. All 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.
+"""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.
+"""
 
-# 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 argparse
+import gc
+import glob
+import gyp_environment
 import os
+import re
+import shlex
+import subprocess
+import string
+import sys
+import vs_toolchain
 
-path = os.path.abspath(os.path.split(__file__)[0])
-execfile(os.path.join(path, 'gyp_chromium'))
+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, 'ios', 'chrome', '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, 'build'))
+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
+
+
+def 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.
+  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', '')
+    cmd = [os.path.join(python_dir, 'python.exe')] + sys.argv
+    sys.exit(subprocess.call(cmd, env=env))
+
+  # This could give false positives since it doesn't actually do real option
+  # parsing.  Oh well.
+  gyp_file_specified = any(arg.endswith('.gyp') for arg in args)
+
+  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')
+
+  # libtool on Mac warns about duplicate basenames in static libraries, so
+  # they're disallowed in general by gyp. We are lax on this point, so disable
+  # this check other than on Mac. GN does not use static libraries as heavily,
+  # so over time this restriction will mostly go away anyway, even on Mac.
+  # https://code.google.com/p/gyp/issues/detail?id=384
+  if sys.platform != 'darwin':
+    args.append('--no-duplicate-basename-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)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/gyp_chromium_test.py b/build/gyp_chromium_test.py
index 0c0e479..0ae74fa 100755
--- a/build/gyp_chromium_test.py
+++ b/build/gyp_chromium_test.py
@@ -14,9 +14,7 @@
 
 import mock
 
-# TODO(sbc): Make gyp_chromium more testable by putting the code in
-# a .py file.
-gyp_chromium = __import__('gyp_chromium')
+import gyp_chromium
 
 
 class TestGetOutputDirectory(unittest.TestCase):
diff --git a/build/gypi_to_gn.py b/build/gypi_to_gn.py
index a107f94..6de1a63 100644
--- a/build/gypi_to_gn.py
+++ b/build/gypi_to_gn.py
@@ -96,10 +96,12 @@
   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.
+  # Strip targets and includes in the toplevel, since some files define these
+  # and we can't slurp them in.
   if 'targets' in file_data:
     del file_data['targets']
+  if 'includes' in file_data:
+    del file_data['includes']
 
   return file_data
 
diff --git a/build/host_jar.gypi b/build/host_jar.gypi
index 9c35177..59e0f25 100644
--- a/build/host_jar.gypi
+++ b/build/host_jar.gypi
@@ -53,6 +53,13 @@
     'jar_path': '<(jar_dir)/<(jar_name)',
     'main_class%': '',
     'stamp': '<(intermediate_dir)/jar.stamp',
+    'conditions': [
+      ['chromium_code == 0', {
+        'enable_errorprone': 0,
+      }],
+    ],
+    'enable_errorprone%': 0,
+    'errorprone_exe_path': '<(PRODUCT_DIR)/bin.java/chromium_errorprone',
   },
   'all_dependent_settings': {
     'variables': {
@@ -64,18 +71,25 @@
       'action_name': 'javac_<(_target_name)',
       'message': 'Compiling <(_target_name) java sources',
       'variables': {
-        'extra_options': [],
+        'extra_args': [],
+        'extra_inputs': [],
         '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)']
+            'extra_args': ['--jar-excluded-classes=<(jar_excluded_classes)']
           }],
           ['main_class != ""', {
-            'extra_options': ['--main-class=>(main_class)']
-          }]
+            'extra_args': ['--main-class=>(main_class)']
+          }],
+          ['enable_errorprone == 1', {
+            'extra_inputs': [
+              '<(errorprone_exe_path)',
+            ],
+            'extra_args': [ '--use-errorprone-path=<(errorprone_exe_path)' ],
+          }],
         ],
       },
       'inputs': [
@@ -83,6 +97,7 @@
         '<(DEPTH)/build/android/gyp/javac.py',
         '^@(java_sources)',
         '>@(input_jars_paths)',
+        '<@(extra_inputs)',
       ],
       'outputs': [
         '<(jar_path)',
@@ -95,7 +110,7 @@
         '--chromium-code=<(chromium_code)',
         '--stamp=<(stamp)',
         '--jar-path=<(jar_path)',
-        '<@(extra_options)',
+        '<@(extra_args)',
         '^@(java_sources)',
       ],
     },
@@ -125,7 +140,12 @@
           ]
         }
       ]
-    }]
+    }],
+    ['enable_errorprone == 1', {
+      'dependencies': [
+        '<(DEPTH)/third_party/errorprone/errorprone.gyp:require_errorprone',
+      ],
+    }],
   ]
 }
 
diff --git a/build/install-android-sdks.sh b/build/install-android-sdks.sh
deleted file mode 100755
index 5c4edaf..0000000
--- a/build/install-android-sdks.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/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
index cf87381..9c3692c 100755
--- a/build/install-build-deps-android.sh
+++ b/build/install-build-deps-android.sh
@@ -13,11 +13,10 @@
 # past the curses-based dialog press TAB <ret> TAB <ret> to agree.
 
 args="$@"
+
+# TODO(dgn) remove this this argument from calls (http://crbug.com/541727)
 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
@@ -92,9 +91,4 @@
   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.py b/build/install-build-deps.py
new file mode 100755
index 0000000..7cc3760
--- /dev/null
+++ b/build/install-build-deps.py
@@ -0,0 +1,430 @@
+#!/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 argparse
+import operator
+import os
+import platform
+import re
+import subprocess
+import sys
+
+
+SUPPORTED_UBUNTU_VERSIONS = (
+  {'number': '12.04', 'codename': 'precise'},
+  {'number': '14.04', 'codename': 'trusty'},
+  {'number': '14.10', 'codename': 'utopic'},
+  {'number': '15.04', 'codename': 'vivid'},
+)
+
+
+# Packages needed for chromeos only.
+_packages_chromeos_dev = (
+  'libbluetooth-dev',
+  'libxkbcommon-dev',
+  'realpath',
+)
+
+
+# Packages needed for development.
+_packages_dev = (
+  'apache2.2-bin',
+  'bison',
+  'cdbs',
+  'curl',
+  'devscripts',
+  'dpkg-dev',
+  'elfutils',
+  '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',
+  'libav-tools',
+  'libbrlapi-dev',
+  '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',
+  'python-yaml',
+  'rpm',
+  'ruby',
+  'subversion',
+  'ttf-dejavu-core',
+  'ttf-indic-fonts',
+  'ttf-kochi-gothic',
+  'ttf-kochi-mincho',
+  'wdiff',
+  'xfonts-mathml',
+  'zip',
+)
+
+
+# Run-time libraries required by chromeos only.
+_packages_chromeos_lib = (
+  'libbz2-1.0',
+  'libpulse0',
+)
+
+
+# Full list of required run-time libraries.
+_packages_lib = (
+  'libasound2',
+  'libatk1.0-0',
+  'libc6',
+  'libcairo2',
+  'libcap2',
+  'libcups2',
+  'libexif12',
+  'libexpat1',
+  'libfontconfig1',
+  'libfreetype6',
+  'libglib2.0-0',
+  'libgnome-keyring0',
+  'libgtk2.0-0',
+  'libpam0g',
+  'libpango1.0-0',
+  'libpci3',
+  'libpcre3',
+  'libpixman-1-0',
+  'libpng12-0',
+  'libspeechd2',
+  'libsqlite3-0',
+  'libstdc++6',
+  'libx11-6',
+  'libxau6',
+  'libxcb1',
+  'libxcomposite1',
+  'libxcursor1',
+  'libxdamage1',
+  'libxdmcp6',
+  'libxext6',
+  'libxfixes3',
+  'libxi6',
+  'libxinerama1',
+  'libxrandr2',
+  'libxrender1',
+  'libxtst6',
+  'zlib1g',
+)
+
+
+# Debugging symbols for all of the run-time libraries.
+_packages_dbg = (
+  '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',
+)
+
+
+# 32-bit libraries needed e.g. to compile V8 snapshot for Android or armhf.
+_packages_lib32 = (
+  'linux-libc-dev:i386',
+)
+
+
+# arm cross toolchain packages needed to build chrome on armhf.
+_packages_arm = (
+  'g++-arm-linux-gnueabihf',
+  'libc6-dev-armhf-cross',
+  'linux-libc-dev-armhf-cross',
+)
+
+
+# Packages to build NaCl, its toolchains, and its ports.
+_packages_naclports = (
+  'ant',
+  'autoconf',
+  'bison',
+  'cmake',
+  'gawk',
+  'intltool',
+  'xsltproc',
+  'xutils-dev',
+)
+_packages_nacl = (
+  'g++-mingw-w64-i686',
+  'lib32ncurses5-dev',
+  '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',
+  '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',
+)
+
+
+def is_userland_64_bit():
+  return platform.architecture()[0] == '64bit'
+
+
+def package_exists(pkg):
+  return pkg in subprocess.check_output(['apt-cache', 'pkgnames']).splitlines()
+
+
+def lsb_release_short_codename():
+  return subprocess.check_output(
+      ['lsb_release', '--codename', '--short']).strip()
+
+
+def write_error(message):
+  sys.stderr.write('ERROR: %s\n' % message)
+  sys.stderr.flush()
+
+
+def nonfatal_get_output(*popenargs, **kwargs):
+  process = subprocess.Popen(
+      stdout=subprocess.PIPE, stderr=subprocess.PIPE, *popenargs, **kwargs)
+  stdout, stderr = process.communicate()
+  retcode = process.poll()
+  return retcode, stdout, stderr
+
+
+def compute_dynamic_package_lists():
+  global _packages_arm
+  global _packages_dbg
+  global _packages_dev
+  global _packages_lib
+  global _packages_lib32
+  global _packages_nacl
+
+  if is_userland_64_bit():
+    # 64-bit systems need a minimum set of 32-bit compat packages
+    # for the pre-built NaCl binaries.
+    _packages_dev += (
+      'lib32gcc1',
+      'lib32stdc++6',
+      'libc6-i386',
+    )
+
+    # 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.
+    # 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.
+    output = subprocess.check_output(['apt-cache', 'depends', 'g++-multilib'])
+    multilib_package = re.search(r'g\+\+-[0-9.]+-multilib', output).group()
+    _packages_lib32 += (multilib_package,)
+
+  lsb_codename = lsb_release_short_codename()
+
+  # Find the proper version of libstdc++6-4.x-dbg.
+  if lsb_codename == 'precise':
+    _packages_dbg += ('libstdc++6-4.6-dbg',)
+  elif lsb_codename == 'trusty':
+    _packages_dbg += ('libstdc++6-4.8-dbg',)
+  else:
+    _packages_dbg += ('libstdc++6-4.9-dbg',)
+
+  # Work around for dependency issue Ubuntu/Trusty: http://crbug.com/435056 .
+  if lsb_codename == 'trusty':
+    _packages_arm += (
+      'g++-4.8-multilib-arm-linux-gnueabihf',
+      'gcc-4.8-multilib-arm-linux-gnueabihf',
+    )
+
+  # 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'):
+    rc, stdout, stderr = nonfatal_get_output(
+        ['dpkg-query', '-Wf\'{Status}\'', 'libgl1-mesa-glx' + variant])
+    if 'ok installed' in output:
+      mesa_variant = variant
+  _packages_dev += (
+    'libgbm-dev' + mesa_variant,
+    'libgl1-mesa-dev' + mesa_variant,
+    'libgles2-mesa-dev' + mesa_variant,
+    'mesa-common-dev' + mesa_variant,
+  )
+
+  if package_exists('ttf-mscorefonts-installer'):
+    _packages_dev += ('ttf-mscorefonts-installer',)
+  else:
+    _packages_dev += ('msttcorefonts',)
+
+  if package_exists('libnspr4-dbg'):
+    _packages_dbg += ('libnspr4-dbg', 'libnss3-dbg')
+    _packages_lib += ('libnspr4', 'libnss3')
+  else:
+    _packages_dbg += ('libnspr4-0d-dbg', 'libnss3-1d-dbg')
+    _packages_lib += ('libnspr4-0d', 'libnss3-1d')
+
+  if package_exists('libjpeg-dev'):
+    _packages_dev += ('libjpeg-dev',)
+  else:
+    _packages_dev += ('libjpeg62-dev',)
+
+  if package_exists('libudev1'):
+    _packages_dev += ('libudev1',)
+    _packages_nacl += ('libudev1:i386',)
+  else:
+    _packages_dev += ('libudev0',)
+    _packages_nacl += ('libudev0:i386',)
+
+  if package_exists('libbrlapi0.6'):
+    _packages_dev += ('libbrlapi0.6',)
+  else:
+    _packages_dev += ('libbrlapi0.5',)
+
+  # Some packages are only needed if the distribution actually supports
+  # installing them.
+  if package_exists('appmenu-gtk'):
+    _packages_lib += ('appmenu-gtk',)
+
+  _packages_dev += _packages_chromeos_dev
+  _packages_lib += _packages_chromeos_lib
+  _packages_nacl += _packages_naclports
+
+
+def quick_check(packages):
+  rc, stdout, stderr = nonfatal_get_output([
+      'dpkg-query', '-W', '-f', '${PackageSpec}:${Status}\n'] + list(packages))
+  if rc == 0 and not stderr:
+    return 0
+  print stderr
+  return 1
+
+
+def main(argv):
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--quick-check', action='store_true',
+                      help='quickly try to determine if dependencies are '
+                           'installed (this avoids interactive prompts and '
+                           'sudo commands so might not be 100% accurate)')
+  parser.add_argument('--unsupported', action='store_true',
+                      help='attempt installation even on unsupported systems')
+  args = parser.parse_args(argv)
+
+  lsb_codename = lsb_release_short_codename()
+  if not args.unsupported and not args.quick_check:
+    if lsb_codename not in map(
+        operator.itemgetter('codename'), SUPPORTED_UBUNTU_VERSIONS):
+      supported_ubuntus = ['%(number)s (%(codename)s)' % v
+                           for v in SUPPORTED_UBUNTU_VERSIONS]
+      write_error('Only Ubuntu %s are currently supported.' %
+                  ', '.join(supported_ubuntus))
+      return 1
+
+    if platform.machine() not in ('i686', 'x86_64'):
+      write_error('Only x86 architectures are currently supported.')
+      return 1
+
+  if os.geteuid() != 0 and not args.quick_check:
+    print 'Running as non-root user.'
+    print 'You might have to enter your password one or more times'
+    print 'for \'sudo\'.'
+    print
+
+  compute_dynamic_package_lists()
+
+  packages = (_packages_dev + _packages_lib + _packages_dbg + _packages_lib32 +
+              _packages_arm + _packages_nacl)
+  def packages_key(pkg):
+    s = pkg.rsplit(':', 1)
+    if len(s) == 1:
+      return (s, '')
+    return s
+  packages = sorted(set(packages), key=packages_key)
+
+  if args.quick_check:
+    return quick_check(packages)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index 2a2d50b..cb5ec20 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -94,7 +94,7 @@
 fi
 
 # Packages needed for chromeos only
-chromeos_dev_list="libbluetooth-dev libxkbcommon-dev"
+chromeos_dev_list="libbluetooth-dev libxkbcommon-dev realpath"
 
 # Packages needed for development
 dev_list="apache2.2-bin bison cdbs curl dpkg-dev elfutils devscripts fakeroot
@@ -102,19 +102,20 @@
           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"
+          libdrm-dev libelf-dev libexif-dev libffi-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 python-yaml 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
+if file -L /sbin/init | grep -q 'ELF 64-bit'; then
   dev_list="${dev_list} libc6-i386 lib32gcc1 lib32stdc++6"
 fi
 
@@ -123,15 +124,15 @@
 
 # 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
+          libexif12 libffi6 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
+dbg_list="libatk1.0-dbg libc6-dbg libcairo2-dbg libffi6-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
@@ -173,16 +174,25 @@
            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
+# Find the proper version of packages that depend on mesa. Only one -lts variant
+# of mesa can be installed and everything that depends on it must match.
+
+# Query for the name and status of all mesa LTS variants, filter for only
+# installed packages, extract just the name, and eliminate duplicates (there can
+# be more than one with the same name in the case of multiarch). Expand into an
+# array.
+mesa_packages=($(dpkg-query -Wf'${package} ${status}\n' \
+                            libgl1-mesa-glx-lts-\* | \
+                 grep " ok installed" | cut -d " " -f 1 | sort -u))
+if [ "${#mesa_packages[@]}" -eq 0 ]; then
+  mesa_variant=""
+elif [ "${#mesa_packages[@]}" -eq 1 ]; then
+  # Strip the base package name and leave just "-lts-whatever"
+  mesa_variant="${mesa_packages[0]#libgl1-mesa-glx}"
+else
+  echo "ERROR: unable to determine which libgl1-mesa-glx variant is installed."
+  exit 1
+fi
 dev_list="${dev_list} libgbm-dev${mesa_variant}
           libgles2-mesa-dev${mesa_variant} libgl1-mesa-dev${mesa_variant}
           mesa-common-dev${mesa_variant}"
@@ -229,7 +239,7 @@
 # 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
+if file -L /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
diff --git a/build/install-chroot.sh b/build/install-chroot.sh
index e2d558b..99451ed 100755
--- a/build/install-chroot.sh
+++ b/build/install-chroot.sh
@@ -223,7 +223,8 @@
       d|D) sudo rm -rf "/var/lib/chroot/${target}"      \
                        "/usr/local/bin/${target%bit}"   \
                        "/etc/schroot/mount-${target}"   \
-                       "/etc/schroot/script-${target}"
+                       "/etc/schroot/script-${target}"  \
+                       "/etc/schroot/${target}"
            sudo sed -ni '/^[[]'"${target%bit}"']$/,${
                          :1;n;/^[[]/b2;b1;:2;p;n;b2};p' \
                        "/etc/schroot/schroot.conf"
@@ -349,13 +350,41 @@
 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 &&
+
+if [ -d '/etc/schroot/default' ]; then
+  new_version=1
+  fstab="/etc/schroot/${target}/fstab"
+else
+  new_version=0
+  fstab="/etc/schroot/mount-${target}"
+fi
+
+if [ "$new_version" = "1" ]; then
+  sudo cp -ar /etc/schroot/default /etc/schroot/${target}
+
+  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)
+profile=${target}
+
+EOF
+  [ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] &&
+    printf "${bind_mounts}" |
+      sudo sh -c "cat >>${fstab}"
+else
+  # 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
+  sudo sh -c 'cat >>/etc/schroot/schroot.conf' <<EOF
 [${target%bit}]
 description=${brand} ${distname} ${arch}
 type=directory
@@ -369,42 +398,43 @@
 
 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}"
+  # Set up a list of mount points that is specific to this
+  # chroot environment.
+  sed '/^FSTAB=/s,"[^"]*","'"${fstab}"'",' \
+           /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 > ${fstab}"
+fi
 
 # 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}"
+    sudo sh -c 'cat >>'"${fstab}"
 
 # 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
+   ! grep -qs '^/media' "${fstab}"; then
   echo '/media /media none rw,rbind 0 0' |
-    sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
+    sudo sh -c 'cat >>'"${fstab}"
 fi
 
 # Share /dev/shm, /run and /run/shm.
-grep -qs '^/dev/shm' /etc/schroot/mount-"${target}" ||
+grep -qs '^/dev/shm' "${fstab}" ||
   echo '/dev/shm /dev/shm none rw,bind 0 0' |
-    sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
+    sudo sh -c 'cat >>'"${fstab}"
 if [ ! -d "/var/lib/chroot/${target}/run" ] &&
-   ! grep -qs '^/run' /etc/schroot/mount-"${target}"; then
+   ! grep -qs '^/run' "${fstab}"; then
   echo '/run /run none rw,bind 0 0' |
-    sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
+    sudo sh -c 'cat >>'"${fstab}"
 fi
-if ! grep -qs '^/run/shm' /etc/schroot/mount-"${target}"; then
+if ! grep -qs '^/run/shm' "${fstab}"; 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}"
+    sudo sh -c 'cat >>'"${fstab}"
 fi
 
 # Set up a special directory that changes contents depending on the target
@@ -412,7 +442,7 @@
 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}"
+  sudo sh -c 'cat >>'"${target}"
 mkdir -p "${s}"
 
 # Install a helper script to launch commands in the chroot
@@ -717,7 +747,7 @@
         # 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;
+        sudo /usr/local/bin/"${target%bit}" sh -c "${script};
               rc=$?;
               /etc/init.d/cron stop >/dev/null 2>&1 || :;
               /etc/init.d/rsyslog stop >/dev/null 2>&1 || :;
diff --git a/build/internal/release_impl_official.gypi b/build/internal/release_impl_official.gypi
index d0729a9..36d5d78 100644
--- a/build/internal/release_impl_official.gypi
+++ b/build/internal/release_impl_official.gypi
@@ -8,7 +8,6 @@
     '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
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index e25efbc..fc9e66e 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -1,73 +1,30 @@
-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_APPLE_FLAGS_HTML
+IDR_AUTOFILL_TOOLTIP_ICON
+IDR_AUTOFILL_TOOLTIP_ICON_H
 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_MD_POLICY_HTML
 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
@@ -80,91 +37,40 @@
 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_32BIT
+IDS_ABOUT_VERSION_64BIT
 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_CLOSE
 IDS_ACCNAME_FORWARD
 IDS_ACCNAME_LOCATION
 IDS_ACCNAME_VOICE_SEARCH
 IDS_ALLOW_INSECURE_CONTENT_BUTTON
+IDS_ALLOW_INSECURE_LOCALHOST
+IDS_ALLOW_INSECURE_LOCALHOST_DESCRIPTION
 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_AUTOFILL_CARD_UNMASK_CONFIRM_BUTTON
+IDS_AUTOFILL_CARD_UNMASK_EXPIRATION_DATE_SEPARATOR
+IDS_AUTOFILL_CARD_UNMASK_INVALID_EXPIRATION_DATE
+IDS_AUTOFILL_CARD_UNMASK_NEW_CARD_LINK
+IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_CHECKBOX
+IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_TOOLTIP_IOS
+IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_IN_PROGRESS
+IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_SUCCESS
+IDS_AUTOFILL_CLEAR_LOCAL_COPY_BUTTON
+IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC
 IDS_AUTOLOGIN_INFOBAR_CANCEL_BUTTON
 IDS_AUTOLOGIN_INFOBAR_MESSAGE
 IDS_AUTOLOGIN_INFOBAR_OK_BUTTON
@@ -172,24 +78,6 @@
 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
@@ -206,58 +94,7 @@
 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_CHILD_AVATAR_LABEL
 IDS_CHROME_TO_DEVICE_PRINT_TO_PHONE
 IDS_CHROME_TO_DEVICE_SNAPSHOTS
 IDS_CLOSE
@@ -277,12 +114,6 @@
 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
@@ -308,27 +139,10 @@
 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_DIAGNOSE
 IDS_ERRORPAGES_BUTTON_LESS
 IDS_ERRORPAGES_BUTTON_MORE
 IDS_ERRORPAGES_BUTTON_RELOAD
@@ -363,7 +177,6 @@
 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
@@ -371,13 +184,12 @@
 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_TEMPORARY_BACKOFF
 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
@@ -404,18 +216,11 @@
 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
@@ -445,13 +250,13 @@
 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_TEMPORARY_BACKOFF
 IDS_ERRORPAGES_SUMMARY_TIMED_OUT
 IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS
 IDS_ERRORPAGES_SUMMARY_WEAK_SERVER_EPHEMERAL_DH_KEY
@@ -461,9 +266,9 @@
 IDS_ERRORPAGES_TITLE_LOAD_FAILED
 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE
 IDS_ERRORPAGES_TITLE_NOT_FOUND
+IDS_ERRORPAGE_FUN_DISABLED
 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
@@ -472,170 +277,14 @@
 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_HELPER_NAME
 IDS_HISTORY_ACTION_MENU_DESCRIPTION
 IDS_HISTORY_BLOCKED_VISIT_TEXT
 IDS_HISTORY_BROWSERESULTS
@@ -643,15 +292,16 @@
 IDS_HISTORY_DATE_WITH_RELATIVE_TIME
 IDS_HISTORY_DELETE_PRIOR_VISITS_CONFIRM_BUTTON
 IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING
+IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING_NO_INCOGNITO
 IDS_HISTORY_FILTER_ALLOWED
 IDS_HISTORY_FILTER_ALLOW_ITEMS
 IDS_HISTORY_FILTER_BLOCKED
 IDS_HISTORY_FILTER_BLOCK_ITEMS
+IDS_HISTORY_FOUND_SEARCH_RESULTS
 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
@@ -661,6 +311,10 @@
 IDS_HISTORY_NUMBER_VISITS
 IDS_HISTORY_OLDER
 IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG
+IDS_HISTORY_OTHER_DEVICES_X_MORE
+IDS_HISTORY_OTHER_SESSIONS_COLLAPSE_SESSION
+IDS_HISTORY_OTHER_SESSIONS_EXPAND_SESSION
+IDS_HISTORY_OTHER_SESSIONS_OPEN_ALL
 IDS_HISTORY_RANGE_ALL_TIME
 IDS_HISTORY_RANGE_LABEL
 IDS_HISTORY_RANGE_MONTH
@@ -673,21 +327,17 @@
 IDS_HISTORY_REMOVE_SELECTED_ITEMS
 IDS_HISTORY_SEARCHRESULTSFOR
 IDS_HISTORY_SEARCH_BUTTON
+IDS_HISTORY_SEARCH_RESULT
+IDS_HISTORY_SEARCH_RESULTS
 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_LEGACY_SUPERVISED_USER_NEW_AVATAR_LABEL
 IDS_LIBADDRESSINPUT_ADDRESS_LINE_1_LABEL
 IDS_LIBADDRESSINPUT_AREA
 IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL
@@ -729,7 +379,6 @@
 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
@@ -746,7 +395,6 @@
 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
@@ -754,16 +402,10 @@
 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
@@ -779,14 +421,12 @@
 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_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR
+IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MINOR
 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
@@ -794,26 +434,20 @@
 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_PASSWORD_MANAGER_SMART_LOCK
 IDS_PAST_TIME_TODAY
 IDS_PAST_TIME_YESTERDAY
 IDS_PDF_INFOBAR_ALWAYS_USE_READER_BUTTON
@@ -823,104 +457,13 @@
 IDS_PHISHING_V3_HEADING
 IDS_PHISHING_V3_PRIMARY_PARAGRAPH
 IDS_PHISHING_V3_PROCEED_PARAGRAPH
+IDS_PHISHING_V4_HEADING
+IDS_PHISHING_V4_PRIMARY_PARAGRAPH
+IDS_PHISHING_V4_PROCEED_AND_REPORT_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
@@ -930,9 +473,11 @@
 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_RECENTLY_CLOSED
 IDS_RECENT_TABS_MENU
+IDS_SAD_TAB_HELP_LINK
+IDS_SAD_TAB_HELP_MESSAGE
 IDS_SAD_TAB_MESSAGE
 IDS_SAD_TAB_RELOAD_LABEL
 IDS_SAD_TAB_TITLE
@@ -940,95 +485,36 @@
 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_SAVE_PASSWORD
+IDS_SAVE_PASSWORD_TITLE_BRAND
 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_SHOWFULLHISTORY_LINK
 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
@@ -1047,7 +533,6 @@
 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
@@ -1058,7 +543,6 @@
 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
@@ -1082,8 +566,6 @@
 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
@@ -1115,29 +597,18 @@
 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_VERSION_UI_COMMAND_LINE
+IDS_VERSION_UI_EXECUTABLE_PATH
+IDS_VERSION_UI_OFFICIAL
+IDS_VERSION_UI_OS
+IDS_VERSION_UI_PATH_NOTFOUND
+IDS_VERSION_UI_PROFILE_PATH
+IDS_VERSION_UI_REVISION
+IDS_VERSION_UI_TITLE
+IDS_VERSION_UI_UNOFFICIAL
+IDS_VERSION_UI_USER_AGENT
+IDS_VERSION_UI_VARIATIONS
 IDS_WEB_FONT_FAMILY
 IDS_WEB_FONT_SIZE
diff --git a/build/isolate.gypi b/build/isolate.gypi
index 10033da..fc82a15 100644
--- a/build/isolate.gypi
+++ b/build/isolate.gypi
@@ -89,7 +89,6 @@
         '--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)',
@@ -106,15 +105,10 @@
       '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)',
+            '--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',
@@ -124,6 +118,15 @@
             '<(PRODUCT_DIR)/<(RULE_INPUT_ROOT).isolated',
           ],
         }],
+        ['OS=="win"', {
+          'action': [
+            '--config-variable', 'msvs_version=<(MSVS_VERSION)',
+          ],
+        }, {
+          'action': [
+            '--config-variable', 'msvs_version=0',
+          ],
+        }],
       ],
     },
   ],
diff --git a/build/jar_file_jni_generator.gypi b/build/jar_file_jni_generator.gypi
index 3d95b28..71ab006 100644
--- a/build/jar_file_jni_generator.gypi
+++ b/build/jar_file_jni_generator.gypi
@@ -61,6 +61,11 @@
       'process_outputs_as_sources': 1,
     },
   ],
+  '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/java.gypi b/build/java.gypi
index 716eb34..ab6687f 100644
--- a/build/java.gypi
+++ b/build/java.gypi
@@ -61,8 +61,9 @@
     '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',
+    'emma_instr_stamp': '<(intermediate_dir)/emma_instr.stamp',
     'additional_input_paths': [],
+    'additional_locale_input_paths': [],
     'dex_path': '<(PRODUCT_DIR)/lib.java/<(_target_name).dex.jar',
     'generated_src_dirs': ['>@(generated_R_dirs)'],
     'generated_R_dirs': [],
@@ -70,7 +71,6 @@
     'res_extra_dirs': [],
     'res_extra_files': [],
     'res_v14_skip%': 0,
-    'res_v14_verify_only%': 0,
     'resource_input_paths': ['>@(res_extra_files)'],
     'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)',
     'compile_stamp': '<(intermediate_dir)/compile.stamp',
@@ -80,6 +80,7 @@
     'never_lint%': 0,
     'findbugs_stamp': '<(intermediate_dir)/findbugs.stamp',
     'run_findbugs%': 0,
+    'java_in_dir_suffix%': '/src',
     'proguard_config%': '',
     'proguard_preprocess%': '0',
     'variables': {
@@ -102,6 +103,13 @@
     },
     'emma_instrument': '<(emma_instrument)',
     'javac_jar_path': '<(javac_jar_path)',
+    'conditions': [
+      ['chromium_code == 0', {
+        'enable_errorprone': 0,
+      }],
+    ],
+    'enable_errorprone%': 0,
+    'errorprone_exe_path': '<(PRODUCT_DIR)/bin.java/chromium_errorprone',
   },
   'conditions': [
     ['add_to_dependents_classpaths == 1', {
@@ -126,6 +134,7 @@
         'generated_src_dirs': ['<(R_dir)'],
         'additional_input_paths': ['<(resource_zip_path)', ],
 
+        'dependencies_locale_zip_paths': [],
         'dependencies_res_zip_paths': [],
         'resource_zip_path': '<(PRODUCT_DIR)/res.java/<(_target_name).zip',
       },
@@ -157,13 +166,14 @@
             # the list of inputs changes.
             'inputs_list_file': '>|(java_resources.<(_target_name).gypcmd >@(resource_input_paths))',
             'process_resources_options': [],
+            'local_dependencies_res_zip_paths': [
+              '>@(dependencies_res_zip_paths)',
+              '>@(dependencies_locale_zip_paths)'
+            ],
             'conditions': [
               ['res_v14_skip == 1', {
                 'process_resources_options': ['--v14-skip']
               }],
-              ['res_v14_verify_only == 1', {
-                'process_resources_options': ['--v14-verify-only']
-              }],
             ],
           },
           'inputs': [
@@ -171,7 +181,7 @@
             '<(DEPTH)/build/android/gyp/process_resources.py',
             '<(DEPTH)/build/android/gyp/generate_v14_compatible_resources.py',
             '>@(resource_input_paths)',
-            '>@(dependencies_res_zip_paths)',
+            '>@(local_dependencies_res_zip_paths)',
             '>(inputs_list_file)',
           ],
           'outputs': [
@@ -180,13 +190,14 @@
           'action': [
             'python', '<(DEPTH)/build/android/gyp/process_resources.py',
             '--android-sdk', '<(android_sdk)',
-            '--android-sdk-tools', '<(android_sdk_tools)',
-            '--non-constant-id',
+            '--aapt-path', '<(android_aapt_path)',
+            # Need to generate onResourcesLoaded() in R.java, so could be used in java lib.
+            '--shared-resources',
 
             '--android-manifest', '<(android_manifest)',
             '--custom-package', '<(R_package)',
 
-            '--dependencies-res-zips', '>(dependencies_res_zip_paths)',
+            '--dependencies-res-zips', '>(local_dependencies_res_zip_paths)',
             '--resource-dirs', '<(res_input_dirs)',
 
             '--R-dir', '<(R_dir)',
@@ -203,7 +214,7 @@
           'action_name': 'proguard_<(_target_name)',
           'message': 'Proguard preprocessing <(_target_name) jar',
           'inputs': [
-            '<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+            '<(DEPTH)/third_party/proguard/lib/proguard.jar',
             '<(DEPTH)/build/android/gyp/util/build_utils.py',
             '<(DEPTH)/build/android/gyp/proguard.py',
             '<(javac_jar_path)',
@@ -214,7 +225,7 @@
           ],
           'action': [
             'python', '<(DEPTH)/build/android/gyp/proguard.py',
-            '--proguard-path=<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+            '--proguard-path=<(DEPTH)/third_party/proguard/lib/proguard.jar',
             '--input-path=<(javac_jar_path)',
             '--output-path=<(jar_path)',
             '--proguard-config=<(proguard_config)',
@@ -228,6 +239,17 @@
         {
           'action_name': 'findbugs_<(_target_name)',
           'message': 'Running findbugs on <(_target_name)',
+          'variables': {
+            'additional_findbugs_args': [],
+            'findbugs_verbose%': 0,
+          },
+          'conditions': [
+            ['findbugs_verbose == 1', {
+              'variables': {
+                'additional_findbugs_args+': ['-vv'],
+              },
+            }],
+          ],
           'inputs': [
             '<(DEPTH)/build/android/findbugs_diff.py',
             '<(DEPTH)/build/android/findbugs_filter/findbugs_exclude.xml',
@@ -243,25 +265,46 @@
             'python', '<(DEPTH)/build/android/findbugs_diff.py',
             '--auxclasspath-gyp', '>(input_jars_paths)',
             '--stamp', '<(findbugs_stamp)',
+            '<@(additional_findbugs_args)',
             '<(jar_final_path)',
           ],
         },
       ],
     }],
+    ['enable_errorprone == 1', {
+      'dependencies': [
+        '<(DEPTH)/third_party/errorprone/errorprone.gyp:require_errorprone',
+      ],
+    }],
   ],
   '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")'],
+        'local_additional_input_paths': [
+          '>@(additional_input_paths)',
+          '>@(additional_locale_input_paths)',
+        ],
+        'extra_args': [],
+        'extra_inputs': [],
+        'java_sources': ['>!@(find >(java_in_dir)>(java_in_dir_suffix) >(additional_src_dirs) -name "*.java")'],
+        'conditions': [
+          ['enable_errorprone == 1', {
+            'extra_inputs': [
+              '<(errorprone_exe_path)',
+            ],
+            'extra_args': [ '--use-errorprone-path=<(errorprone_exe_path)' ],
+          }],
+        ],
       },
       'inputs': [
         '<(DEPTH)/build/android/gyp/util/build_utils.py',
         '<(DEPTH)/build/android/gyp/javac.py',
         '>@(java_sources)',
         '>@(input_jars_paths)',
-        '>@(additional_input_paths)',
+        '>@(local_additional_input_paths)',
+        '<@(extra_inputs)',
       ],
       'outputs': [
         '<(compile_stamp)',
@@ -269,6 +312,7 @@
       ],
       'action': [
         'python', '<(DEPTH)/build/android/gyp/javac.py',
+        '--bootclasspath=<(android_sdk_jar)',
         '--classpath=>(input_jars_paths)',
         '--src-gendirs=>(generated_src_dirs)',
         '--javac-includes=<(javac_includes)',
@@ -277,16 +321,18 @@
         '--jar-excluded-classes=<(jar_excluded_classes)',
         '--stamp=<(compile_stamp)',
         '>@(java_sources)',
+        '<@(extra_args)',
       ]
     },
     {
-      'action_name': 'instr_jar_<(_target_name)',
+      'action_name': 'emma_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',
+        'coverage_file': '<(jar_dir)/<(_target_name).em',
+        'sources_list_file': '<(jar_dir)/<(_target_name)_sources.txt',
+        'stamp_path': '<(emma_instr_stamp)',
       },
       'outputs': [
         '<(jar_final_path)',
@@ -294,12 +340,12 @@
       'inputs': [
         '<(jar_path)',
       ],
-      'includes': [ 'android/instr_action.gypi' ],
+      'includes': [ 'android/emma_instr_action.gypi' ],
     },
     {
       'variables': {
         'src_dirs': [
-          '<(java_in_dir)/src',
+          '<(java_in_dir)<(java_in_dir_suffix)',
           '>@(additional_src_dirs)',
         ],
         'stamp_path': '<(lint_stamp)',
diff --git a/build/java_aidl.gypi b/build/java_aidl.gypi
index 8f111fd..dda2894 100644
--- a/build/java_aidl.gypi
+++ b/build/java_aidl.gypi
@@ -35,6 +35,7 @@
 
 {
   'variables': {
+    'aidl_path%': '<(android_sdk_tools)/aidl',
     'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)/aidl',
     'aidl_import_include%': '',
     'additional_aidl_arguments': [],
@@ -66,7 +67,7 @@
         '<(intermediate_dir)/<(RULE_INPUT_ROOT).java',
       ],
       'action': [
-        '<(android_sdk_tools)/aidl',
+        '<(aidl_path)',
         '-p<(android_sdk)/framework.aidl',
         '-p<(aidl_interface_file)',
         '<@(additional_aidl_arguments)',
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
index 154c16e..2a62d97 100644
--- a/build/java_apk.gypi
+++ b/build/java_apk.gypi
@@ -31,10 +31,16 @@
 #  additional_bundled_libs - Additional libraries what will be stripped and
 #    bundled in the apk.
 #  asset_location - The directory where assets are located.
+#  create_abi_split - Whether to create abi-based spilts. Splits
+#    are supported only for minSdkVersion >= 21.
+#  create_density_splits - Whether to create density-based apk splits.
+#  language_splits - List of languages to create apk splits for.
 #  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).
+#  library_jars_paths - The path to library jars to be included in the classpath.
+#    These will not be included into the final apk.
 #  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
@@ -45,13 +51,15 @@
 #  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.
+#  app_as_shared_library - Make a resource package that can be loaded as shared
+#    library.
 #  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.
 #  include_all_resources - Set to 1 to include all resource IDs in all generated
 #    R.java files.
 #  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
+#  load_library_from_zip - 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.
@@ -62,11 +70,18 @@
 #  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.
+#  dependencies_locale_zip_alternative_paths - a list of paths that used to
+#    replace dependencies_locale_zip_paths of all_dependent_settings.
 {
   'variables': {
     'tested_apk_obfuscated_jar_path%': '/',
     'tested_apk_dex_path%': '/',
+    'tested_apk_is_multidex%': 0,
     'additional_input_paths': [],
+    'additional_locale_input_paths': [],
+    'create_density_splits%': 0,
+    'language_splits': [],
+    'library_jars_paths': [],
     'input_jars_paths': [],
     'library_dexed_jars_paths': [],
     'additional_src_dirs': [],
@@ -76,17 +91,22 @@
     # aapt generates this proguard.txt.
     'generated_proguard_file': '<(intermediate_dir)/proguard.txt',
     'proguard_enabled%': 'false',
+    'debug_build_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%':'',
     'include_all_resources%': 0,
     'additional_R_text_files': [],
+    'dependencies_locale_zip_alternative_paths%': [],
+    'dependencies_locale_zip_paths': [],
     'dependencies_res_zip_paths': [],
     'additional_res_packages': [],
     'additional_bundled_libs%': [],
     'is_test_apk%': 0,
-    'extensions_to_not_compress%': '',
+    # Allow icu data, v8 snapshots, and pak files to be loaded directly from the .apk.
+    # Note: These are actually suffix matches, not necessarily extensions.
+    'extensions_to_not_compress%': '.dat,.bin,.pak',
     'resource_input_paths': [],
     'intermediate_dir': '<(PRODUCT_DIR)/<(_target_name)',
     'asset_location%': '<(intermediate_dir)/assets',
@@ -109,10 +129,10 @@
     'findbugs_stamp': '<(intermediate_dir)/findbugs.stamp',
     'run_findbugs%': 0,
     'java_in_dir_suffix%': '/src',
-    'instr_stamp': '<(intermediate_dir)/instr.stamp',
+    'emma_instr_stamp': '<(intermediate_dir)/emma_instr.stamp',
     'jar_stamp': '<(intermediate_dir)/jar.stamp',
     'obfuscate_stamp': '<(intermediate_dir)/obfuscate.stamp',
-    'pack_arm_relocations_stamp': '<(intermediate_dir)/pack_arm_relocations.stamp',
+    'pack_relocations_stamp': '<(intermediate_dir)/pack_relocations.stamp',
     'strip_stamp': '<(intermediate_dir)/strip.stamp',
     'stripped_libraries_dir': '<(intermediate_dir)/stripped_libraries',
     'strip_additional_stamp': '<(intermediate_dir)/strip_additional.stamp',
@@ -123,18 +143,20 @@
     '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',
+    'enable_multidex%': 0,
+    'enable_multidex_configurations%': [],
+    'multidex_configuration_path': '<(intermediate_dir)/multidex_config.json',
+    'main_dex_list_path': '<(intermediate_dir)/main_dex_list.txt',
     'emma_device_jar': '<(android_sdk_root)/tools/lib/emma_device.jar',
     'android_manifest_path%': '<(java_in_dir)/AndroidManifest.xml',
+    'split_android_manifest_path': '<(intermediate_dir)/split-manifests/<(android_app_abi)/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',
+    'app_as_shared_library%': 0,
+    'final_apk_path_no_extension%': '<(PRODUCT_DIR)/apks/<(apk_name)',
+    'final_abi_split_apk_path%': '<(PRODUCT_DIR)/apks/<(apk_name)-abi-<(android_app_abi).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)',
@@ -142,20 +164,32 @@
     'symlink_script_device_path': '<(device_intermediate_dir)/create_symlinks.sh',
     'create_standalone_apk%': 1,
     'res_v14_skip%': 0,
-    '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,
+        'unsigned_apk_path': '<(intermediate_dir)/<(apk_name)-unsigned.apk',
+        'unsigned_abi_split_apk_path': '<(intermediate_dir)/<(apk_name)-abi-<(android_app_abi)-unsigned.apk',
+        'create_abi_split%': 0,
+        'enable_multidex%': 0,
       },
+      'unsigned_apk_path': '<(unsigned_apk_path)',
+      'unsigned_abi_split_apk_path': '<(unsigned_abi_split_apk_path)',
+      'create_abi_split%': '<(create_abi_split)',
+      'final_apk_path%': '<(PRODUCT_DIR)/apks/<(apk_name).apk',
       'conditions': [
         ['gyp_managed_install == 1 and native_lib_target != ""', {
-          'unsigned_standalone_apk_path': '<(intermediate_dir)/<(apk_name)-standalone-unsigned.apk',
+          'conditions': [
+            ['create_abi_split == 0', {
+              'unsigned_standalone_apk_path': '<(intermediate_dir)/<(apk_name)-standalone-unsigned.apk',
+            }, {
+              'unsigned_standalone_apk_path': '<(intermediate_dir)/<(apk_name)-abi-<(android_app_abi)-standalone-unsigned.apk',
+            }],
+          ],
         }, {
           'unsigned_standalone_apk_path': '<(unsigned_apk_path)',
         }],
@@ -169,21 +203,47 @@
         },{
           'emma_instrument%': 0,
         }],
+        # When using abi splits, the abi split is modified by
+        # gyp_managed_install rather than the main .apk
+        ['create_abi_split == 1', {
+          'managed_input_apk_path': '<(unsigned_abi_split_apk_path)',
+        }, {
+          'managed_input_apk_path': '<(unsigned_apk_path)',
+        }],
+        ['enable_multidex == 1', {
+          'dex_path': '<(intermediate_dir)/classes.dex.zip',
+        }, {
+          'dex_path': '<(intermediate_dir)/classes.dex',
+        }],
       ],
     },
     'native_lib_target%': '',
     'native_lib_version_name%': '',
     'use_chromium_linker%' : 0,
-    'load_library_from_zip_file%' : 0,
+    'load_library_from_zip%' : 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)',
+    'unsigned_apk_path': '<(unsigned_apk_path)',
+    'unsigned_abi_split_apk_path': '<(unsigned_abi_split_apk_path)',
+    'create_abi_split%': '<(create_abi_split)',
+    'managed_input_apk_path': '<(managed_input_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': [],
+    'main_apk_name': '<(apk_name)',
+    'dex_path': '<(dex_path)',
+    'conditions': [
+      ['chromium_code == 0', {
+        'enable_errorprone': 0,
+      }],
+    ],
+    'enable_errorprone%': 0,
+    'errorprone_exe_path': '<(PRODUCT_DIR)/bin.java/chromium_errorprone',
+    'final_apk_path%': '<(final_apk_path)',
   },
   # 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
@@ -195,11 +255,22 @@
           'proguard_enabled': 'true',
         }
       }],
+      ['debug_build_proguard_enabled == "true"', {
+        'variables': {
+          'debug_build_proguard_enabled': 'true',
+        }
+      }],
+      ['is_test_apk == 0', {
+        'variables': {
+          'tested_apk_path': '<(final_apk_path)',
+          'tested_apk_obfuscated_jar_path': '<(obfuscated_jar_path)',
+          'tested_apk_dex_path': '<(dex_path)',
+          'tested_apk_is_multidex': '<(enable_multidex)',
+        }
+      }]
     ],
     'variables': {
       'apk_output_jar_path': '<(jar_path)',
-      'tested_apk_obfuscated_jar_path': '<(obfuscated_jar_path)',
-      'tested_apk_dex_path': '<(dex_path)',
     },
   },
   'conditions': [
@@ -216,7 +287,7 @@
         'additional_R_text_files': ['<(intermediate_dir)/R.txt'],
       },
     }],
-    ['native_lib_target != "" and component == "shared_library"', {
+    ['native_lib_target != "" and android_must_copy_system_libraries == 1', {
       'dependencies': [
         '<(DEPTH)/build/android/setup.gyp:copy_system_libraries',
       ],
@@ -226,6 +297,11 @@
         '<(DEPTH)/base/base.gyp:chromium_android_linker',
       ],
     }],
+    ['enable_errorprone == 1', {
+      'dependencies': [
+        '<(DEPTH)/third_party/errorprone/errorprone.gyp:require_errorprone',
+      ],
+    }],
     ['native_lib_target != ""', {
       'variables': {
         'conditions': [
@@ -286,7 +362,7 @@
                   'linker_gcc_preprocess_defines': [],
                 },
               }],
-              ['load_library_from_zip_file == 1', {
+              ['load_library_from_zip == 1', {
                 'variables': {
                   'linker_load_from_zip_file_preprocess_defines': [
                     '--defines', 'ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE',
@@ -363,7 +439,7 @@
           'includes': ['../build/android/insert_chromium_version.gypi'],
         },
         {
-          'action_name': 'pack_arm_relocations',
+          'action_name': 'pack_relocations',
           'variables': {
             'conditions': [
               ['use_chromium_linker == 1 and use_relocation_packer == 1 and profiling != 1', {
@@ -381,9 +457,9 @@
             'input_paths': [
               '<(version_stamp)'
             ],
-            'stamp': '<(pack_arm_relocations_stamp)',
+            'stamp': '<(pack_relocations_stamp)',
           },
-          'includes': ['../build/android/pack_arm_relocations.gypi'],
+          'includes': ['../build/android/pack_relocations.gypi'],
         },
         {
           'variables': {
@@ -440,7 +516,6 @@
             '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',
@@ -485,11 +560,11 @@
                     'inputs': [
                       '<(ordered_libraries_file)',
                       '<(strip_additional_stamp)',
-                      '<(pack_arm_relocations_stamp)',
+                      '<(pack_relocations_stamp)',
                     ],
-                    'input_apk_path': '<(unsigned_apk_path)',
                     'output_apk_path': '<(unsigned_standalone_apk_path)',
                     'libraries_top_dir%': '<(libraries_top_dir)',
+                    'input_apk_path': '<(managed_input_apk_path)',
                   },
                   'includes': [ 'android/create_standalone_apk_action.gypi' ],
                 },
@@ -502,25 +577,93 @@
             'libraries_source_dir': '<(apk_package_native_libs_dir)/<(android_app_abi)',
             'package_input_paths': [
               '<(strip_additional_stamp)',
-              '<(pack_arm_relocations_stamp)',
+              '<(pack_relocations_stamp)',
             ],
           },
         }],
       ],
     }], # native_lib_target != ''
-    ['gyp_managed_install == 0 or create_standalone_apk == 1', {
+    ['gyp_managed_install == 0 or create_standalone_apk == 1 or create_abi_split == 1', {
+      'dependencies': [
+        '<(DEPTH)/build/android/rezip.gyp:rezip_apk_jar',
+      ],
+    }],
+    ['create_abi_split == 1 or gyp_managed_install == 0 or create_standalone_apk == 1', {
       'actions': [
         {
-          'action_name': 'finalize standalone apk',
+          'action_name': 'finalize_base',
           'variables': {
-            'input_apk_path': '<(unsigned_standalone_apk_path)',
             'output_apk_path': '<(final_apk_path)',
+            'conditions': [
+              ['create_abi_split == 0', {
+                'input_apk_path': '<(unsigned_standalone_apk_path)',
+              }, {
+                'input_apk_path': '<(unsigned_apk_path)',
+                'load_library_from_zip': 0,
+              }]
+            ],
           },
           'includes': [ 'android/finalize_apk_action.gypi']
         },
       ],
-      'dependencies': [
-        '<(DEPTH)/build/android/rezip.gyp:rezip_apk_jar',
+    }],
+    ['create_abi_split == 1', {
+      'actions': [
+        {
+          'action_name': 'generate_split_manifest_<(_target_name)',
+          'inputs': [
+            '<(DEPTH)/build/android/gyp/util/build_utils.py',
+            '<(DEPTH)/build/android/gyp/generate_split_manifest.py',
+            '<(android_manifest_path)',
+          ],
+          'outputs': [
+            '<(split_android_manifest_path)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/generate_split_manifest.py',
+            '--main-manifest', '<(android_manifest_path)',
+            '--out-manifest', '<(split_android_manifest_path)',
+            '--split', 'abi_<(android_app_abi)',
+          ],
+        },
+        {
+          'variables': {
+            'apk_name': '<(main_apk_name)-abi-<(android_app_abi)',
+            'asset_location': '',
+            'android_manifest_path': '<(split_android_manifest_path)',
+            'create_density_splits': 0,
+            'language_splits=': [],
+          },
+          'includes': [ 'android/package_resources_action.gypi' ],
+        },
+        {
+          'variables': {
+            'apk_name': '<(main_apk_name)-abi-<(android_app_abi)',
+            'apk_path': '<(unsigned_abi_split_apk_path)',
+            'has_code': 0,
+            'native_libs_dir': '<(apk_package_native_libs_dir)',
+            'extra_inputs': ['<(native_lib_placeholder_stamp)'],
+          },
+          'includes': ['android/apkbuilder_action.gypi'],
+        },
+      ],
+    }],
+    ['create_abi_split == 1 and (gyp_managed_install == 0 or create_standalone_apk == 1)', {
+      'actions': [
+        {
+          'action_name': 'finalize_split',
+          'variables': {
+            'output_apk_path': '<(final_abi_split_apk_path)',
+            'conditions': [
+              ['gyp_managed_install == 1', {
+                'input_apk_path': '<(unsigned_standalone_apk_path)',
+              }, {
+                'input_apk_path': '<(unsigned_abi_split_apk_path)',
+              }],
+            ],
+          },
+          'includes': [ 'android/finalize_apk_action.gypi']
+        },
       ],
     }],
     ['gyp_managed_install == 1', {
@@ -528,7 +671,8 @@
         {
           'action_name': 'finalize incomplete apk',
           'variables': {
-            'input_apk_path': '<(unsigned_apk_path)',
+            'load_library_from_zip': 0,
+            'input_apk_path': '<(managed_input_apk_path)',
             'output_apk_path': '<(incomplete_apk_path)',
           },
           'includes': [ 'android/finalize_apk_action.gypi']
@@ -547,28 +691,86 @@
           ],
           '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)',
+            '--android-sdk-tools', '<(android_sdk_tools)',
+          ],
+          'conditions': [
+            ['create_abi_split == 1', {
+              'inputs': [
+                '<(final_apk_path)',
+              ],
+              'action': [
+                '--apk-path=<(final_apk_path)',
+                '--split-apk-path=<(incomplete_apk_path)',
+              ],
+            }, {
+              'action': [
+                '--apk-path=<(incomplete_apk_path)',
+              ],
+            }],
+            ['create_density_splits == 1', {
+              'inputs': [
+                '<(final_apk_path_no_extension)-density-hdpi.apk',
+                '<(final_apk_path_no_extension)-density-xhdpi.apk',
+                '<(final_apk_path_no_extension)-density-xxhdpi.apk',
+                '<(final_apk_path_no_extension)-density-xxxhdpi.apk',
+                '<(final_apk_path_no_extension)-density-tvdpi.apk',
+              ],
+              'action': [
+                '--split-apk-path=<(final_apk_path_no_extension)-density-hdpi.apk',
+                '--split-apk-path=<(final_apk_path_no_extension)-density-xhdpi.apk',
+                '--split-apk-path=<(final_apk_path_no_extension)-density-xxhdpi.apk',
+                '--split-apk-path=<(final_apk_path_no_extension)-density-xxxhdpi.apk',
+                '--split-apk-path=<(final_apk_path_no_extension)-density-tvdpi.apk',
+              ],
+            }],
+            ['language_splits != []', {
+              'inputs': [
+                "<!@(python <(DEPTH)/build/apply_locales.py '<(final_apk_path_no_extension)-lang-ZZLOCALE.apk' <(language_splits))",
+              ],
+              'action': [
+                "<!@(python <(DEPTH)/build/apply_locales.py -- '--split-apk-path=<(final_apk_path_no_extension)-lang-ZZLOCALE.apk' <(language_splits))",
+              ],
+            }],
           ],
         },
       ],
-      'dependencies': [
-        '<(DEPTH)/build/android/rezip.gyp:rezip_apk_jar',
+    }],
+    ['create_density_splits == 1', {
+      'actions': [
+        {
+          'action_name': 'finalize_density_splits',
+          'variables': {
+            'density_splits': 1,
+          },
+          'includes': [ 'android/finalize_splits_action.gypi']
+        },
       ],
     }],
     ['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)',
+          'variables': {
+            'additional_findbugs_args': [],
+            'findbugs_verbose%': 0,
+          },
+          'conditions': [
+            ['findbugs_verbose == 1', {
+              'variables': {
+                'additional_findbugs_args+': ['-vv'],
+              },
+            }],
+          ],
           'inputs': [
             '<(DEPTH)/build/android/findbugs_diff.py',
             '<(DEPTH)/build/android/findbugs_filter/findbugs_exclude.xml',
@@ -584,12 +786,44 @@
             'python', '<(DEPTH)/build/android/findbugs_diff.py',
             '--auxclasspath-gyp', '>(input_jars_paths)',
             '--stamp', '<(findbugs_stamp)',
+            '<@(additional_findbugs_args)',
             '<(jar_path)',
           ],
         },
       ],
-    },
-    ]
+    }],
+    ['enable_multidex == 1', {
+      'actions': [
+        {
+          'action_name': 'main_dex_list_for_<(_target_name)',
+          'variables': {
+            'jar_paths': ['>@(input_jars_paths)', '<(javac_jar_path)'],
+            'output_path': '<(main_dex_list_path)',
+          },
+          'includes': [ 'android/main_dex_action.gypi' ],
+        },
+        {
+          'action_name': 'configure_multidex_for_<(_target_name)',
+          'inputs': [
+            '<(DEPTH)/build/android/gyp/configure_multidex.py',
+          ],
+          'outputs': [
+            '<(multidex_configuration_path)',
+          ],
+          'variables': {
+            'additional_multidex_config_options': [],
+            'enabled_configurations': ['>@(enable_multidex_configurations)'],
+          },
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/configure_multidex.py',
+            '--configuration-name', '<(CONFIGURATION_NAME)',
+            '--enabled-configurations', '<(enabled_configurations)',
+            '--multidex-configuration-path', '<(multidex_configuration_path)',
+            '>@(additional_multidex_config_options)',
+          ],
+        },
+      ],
+    }],
   ],
   'dependencies': [
     '<(DEPTH)/tools/android/md5sum/md5sum.gyp:md5sum',
@@ -599,24 +833,39 @@
       'action_name': 'process_resources',
       'message': 'processing resources for <(_target_name)',
       'variables': {
+        'local_additional_input_paths': [
+          '>@(additional_input_paths)',
+        ],
+        'local_dependencies_res_zip_paths': [
+          '>@(dependencies_res_zip_paths)'
+        ],
         # 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))',
+        'inputs_list_file': '>|(apk_codegen.<(_target_name).gypcmd >@(local_additional_input_paths) >@(resource_input_paths))',
+
         'process_resources_options': [],
         'conditions': [
+          ['dependencies_locale_zip_alternative_paths == []', {
+            'local_dependencies_res_zip_paths': ['>@(dependencies_locale_zip_paths)'],
+            'local_additional_input_paths': ['>@(additional_locale_input_paths)']
+          }, {
+            'local_dependencies_res_zip_paths': ['<@(dependencies_locale_zip_alternative_paths)'],
+            'local_additional_input_paths': ['>@(dependencies_locale_zip_alternative_paths)'],
+          }],
           ['is_test_apk == 1', {
+            'dependencies_locale_zip_paths=': [],
             'dependencies_res_zip_paths=': [],
             'additional_res_packages=': [],
           }],
           ['res_v14_skip == 1', {
             'process_resources_options+': ['--v14-skip']
           }],
-          ['res_v14_verify_only == 1', {
-            'process_resources_options+': ['--v14-verify-only']
-          }],
           ['shared_resources == 1', {
             'process_resources_options+': ['--shared-resources']
           }],
+          ['app_as_shared_library == 1', {
+            'process_resources_options+': ['--app-as-shared-lib']
+          }],
           ['R_package != ""', {
             'process_resources_options+': ['--custom-package', '<(R_package)']
           }],
@@ -629,9 +878,9 @@
         '<(DEPTH)/build/android/gyp/util/build_utils.py',
         '<(DEPTH)/build/android/gyp/process_resources.py',
         '<(android_manifest_path)',
-        '>@(additional_input_paths)',
+        '>@(local_additional_input_paths)',
         '>@(resource_input_paths)',
-        '>@(dependencies_res_zip_paths)',
+        '>@(local_dependencies_res_zip_paths)',
         '>(inputs_list_file)',
       ],
       'outputs': [
@@ -642,10 +891,10 @@
       'action': [
         'python', '<(DEPTH)/build/android/gyp/process_resources.py',
         '--android-sdk', '<(android_sdk)',
-        '--android-sdk-tools', '<(android_sdk_tools)',
+        '--aapt-path', '<(android_aapt_path)',
 
         '--android-manifest', '<(android_manifest_path)',
-        '--dependencies-res-zips', '>(dependencies_res_zip_paths)',
+        '--dependencies-res-zips', '>(local_dependencies_res_zip_paths)',
 
         '--extra-res-packages', '>(additional_res_packages)',
         '--extra-r-text-files', '>(additional_R_text_files)',
@@ -666,6 +915,8 @@
       'action_name': 'javac_<(_target_name)',
       'message': 'Compiling java for <(_target_name)',
       'variables': {
+        'extra_args': [],
+        'extra_inputs': [],
         'gen_src_dirs': [
           '<(intermediate_dir)/gen',
           '>@(generated_src_dirs)',
@@ -681,7 +932,14 @@
         # 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)'],
-
+        'conditions': [
+          ['enable_errorprone == 1', {
+            'extra_inputs': [
+              '<(errorprone_exe_path)',
+            ],
+            'extra_args': [ '--use-errorprone-path=<(errorprone_exe_path)' ],
+          }],
+        ],
       },
       'inputs': [
         '<(DEPTH)/build/android/gyp/util/build_utils.py',
@@ -689,6 +947,7 @@
         '>@(java_sources)',
         '>@(input_jars_paths)',
         '<(codegen_stamp)',
+        '<@(extra_inputs)',
       ],
       'conditions': [
         ['native_lib_target != ""', {
@@ -701,33 +960,36 @@
       ],
       'action': [
         'python', '<(DEPTH)/build/android/gyp/javac.py',
-        '--classpath=>(input_jars_paths) <(android_sdk_jar)',
+        '--bootclasspath=<(android_sdk_jar)',
+        '--classpath=>(input_jars_paths) <(android_sdk_jar) >(library_jars_paths)',
         '--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)',
+        '<@(extra_args)',
         '>@(java_sources)',
       ],
     },
     {
-      'action_name': 'instr_jar_<(_target_name)',
+      'action_name': 'emma_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',
+        'coverage_file': '<(PRODUCT_DIR)/lib.java/<(_target_name).em',
+        'sources_list_file': '<(PRODUCT_DIR)/lib.java/<(_target_name)_sources.txt',
+        'stamp_path': '<(emma_instr_stamp)',
       },
       'outputs': [
-        '<(instr_stamp)',
+        '<(emma_instr_stamp)',
         '<(jar_path)',
       ],
       'inputs': [
         '<(javac_jar_path)',
       ],
-      'includes': [ 'android/instr_action.gypi' ],
+      'includes': [ 'android/emma_instr_action.gypi' ],
     },
     {
       'variables': {
@@ -775,6 +1037,11 @@
               '--proguard-enabled',
             ],
           }],
+          ['debug_build_proguard_enabled == "true"', {
+            'additional_obfuscate_options': [
+              '--debug-build-proguard-enabled',
+            ],
+          }],
         ],
         'obfuscate_input_jars_paths': [
           '>@(input_jars_paths)',
@@ -787,6 +1054,18 @@
             '<(test_jar_path)',
           ],
         }],
+        ['enable_multidex == 1', {
+          'inputs': [
+            '<(main_dex_list_path)',
+            '<(multidex_configuration_path)',
+          ],
+          'variables': {
+            'additional_obfuscate_options': [
+              '--main-dex-list-path', '<(main_dex_list_path)',
+              '--multidex-configuration-path', '<(multidex_configuration_path)',
+            ],
+          },
+        }],
       ],
       'inputs': [
         '<(DEPTH)/build/android/gyp/apk_obfuscate.py',
@@ -794,7 +1073,7 @@
         '>@(proguard_flags_paths)',
         '>@(obfuscate_input_jars_paths)',
         '>@(additional_obfuscate_input_paths)',
-        '<(instr_stamp)',
+        '<(emma_instr_stamp)',
       ],
       'outputs': [
         '<(obfuscate_stamp)',
@@ -822,7 +1101,7 @@
         '--test-jar-path', '<(test_jar_path)',
         '--obfuscated-jar-path', '<(obfuscated_jar_path)',
 
-        '--proguard-jar-path', '<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+        '--proguard-jar-path', '<(DEPTH)/third_party/proguard/lib/proguard.jar',
 
         '--stamp', '<(obfuscate_stamp)',
 
@@ -832,14 +1111,41 @@
     {
       'action_name': 'dex_<(_target_name)',
       'variables': {
+        'dex_additional_options': [],
         'dex_input_paths': [
-          '>@(library_dexed_jars_paths)',
           '<(jar_path)',
         ],
         'output_path': '<(dex_path)',
         'proguard_enabled_input_path': '<(obfuscated_jar_path)',
       },
+      'conditions': [
+        ['enable_multidex == 1', {
+          'inputs': [
+            '<(main_dex_list_path)',
+            '<(multidex_configuration_path)',
+          ],
+          'variables': {
+            'dex_additional_options': [
+              '--main-dex-list-path', '<(main_dex_list_path)',
+              '--multidex-configuration-path', '<(multidex_configuration_path)',
+            ],
+          },
+        }],
+      ],
       'target_conditions': [
+        ['enable_multidex == 1 or tested_apk_is_multidex == 1', {
+          'variables': {
+            'dex_input_paths': [
+              '>@(input_jars_paths)',
+            ],
+          },
+        }, {
+          'variables': {
+            'dex_input_paths': [
+              '>@(library_dexed_jars_paths)',
+            ],
+          },
+        }],
         ['emma_instrument != 0', {
           'variables': {
             'dex_no_locals': 1,
@@ -858,118 +1164,51 @@
             '>(tested_apk_dex_path).inputs',
           ],
         }],
-        ['proguard_enabled == "true"', {
+        ['proguard_enabled == "true" or debug_build_proguard_enabled == "true"', {
           'inputs': [ '<(obfuscate_stamp)' ]
         }, {
-          'inputs': [ '<(instr_stamp)' ]
+          'inputs': [ '<(emma_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': [
+        'local_dependencies_res_zip_paths': ['>@(dependencies_res_zip_paths)'],
+        'extra_inputs': ['<(codegen_stamp)'],
+        'resource_zips': [
           '<(resource_zip_path)',
-          '>@(dependencies_res_zip_paths)',
         ],
         'conditions': [
-          ['shared_resources == 1', {
-            'package_resources_options+': ['--shared-resources']
+          ['dependencies_locale_zip_alternative_paths == []', {
+            'local_dependencies_res_zip_paths': ['>@(dependencies_locale_zip_paths)'],
+          }, {
+            'local_dependencies_res_zip_paths': ['<@(dependencies_locale_zip_alternative_paths)'],
+          }],
+          ['is_test_apk == 0', {
+            'resource_zips': [
+              '>@(local_dependencies_res_zip_paths)',
+            ],
           }],
         ],
       },
-      '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)',
-      ],
+      'includes': [ 'android/package_resources_action.gypi' ],
     },
     {
-      '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))'
+        'apk_path': '<(unsigned_apk_path)',
+        'conditions': [
+          ['native_lib_target != ""', {
+            'extra_inputs': ['<(native_lib_placeholder_stamp)'],
+          }],
+          ['create_abi_split == 0', {
+            'native_libs_dir': '<(apk_package_native_libs_dir)',
+          }, {
+            'native_libs_dir': '<(DEPTH)/build/android/ant/empty/res',
+          }],
+        ],
       },
-      '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',
-      ]
+      'includes': ['android/apkbuilder_action.gypi'],
     },
   ],
 }
diff --git a/build/java_prebuilt.gypi b/build/java_prebuilt.gypi
index 8efc4ef..cb654cb 100644
--- a/build/java_prebuilt.gypi
+++ b/build/java_prebuilt.gypi
@@ -24,7 +24,6 @@
   ],
   '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,
@@ -36,9 +35,9 @@
       },
       'conditions': [
         ['proguard_preprocess == 1', {
-          'dex_input_jar_path': '<(intermediate_dir)/<(_target_name).pre.jar'
+          'dex_input_jar_path': '<(PRODUCT_DIR)/lib.java/<(_target_name).pre.jar',
         }, {
-          'dex_input_jar_path': '<(jar_path)'
+          'dex_input_jar_path': '<(jar_path)',
         }],
       ],
     },
@@ -63,7 +62,7 @@
           'action_name': 'proguard_<(_target_name)',
           'message': 'Proguard preprocessing <(_target_name) jar',
           'inputs': [
-            '<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+            '<(DEPTH)/third_party/proguard/lib/proguard.jar',
             '<(DEPTH)/build/android/gyp/util/build_utils.py',
             '<(DEPTH)/build/android/gyp/proguard.py',
             '<(jar_path)',
@@ -74,7 +73,7 @@
           ],
           'action': [
             'python', '<(DEPTH)/build/android/gyp/proguard.py',
-            '--proguard-path=<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+            '--proguard-path=<(DEPTH)/third_party/proguard/lib/proguard.jar',
             '--input-path=<(jar_path)',
             '--output-path=<(dex_input_jar_path)',
             '--proguard-config=<(proguard_config)',
diff --git a/build/json_schema_api.gni b/build/json_schema_api.gni
index aa6365b..24867d1 100644
--- a/build/json_schema_api.gni
+++ b/build/json_schema_api.gni
@@ -31,6 +31,11 @@
 # bundle_registration [optional, default = false]
 #   Boolean indicating if the API registration bundle files should be generated.
 #
+# bundle_name [required if bundle or bundle_registrations]:
+#     A string to prepend to generated bundle class names, so that multiple
+#     bundle rules can be used without conflicting.  Only used with one of
+#     the cpp-bundle generators.
+#
 # 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
@@ -42,6 +47,9 @@
 #   A list of schema files which should not be compiled, but which should still
 #   be processed for API bundle generation.
 #
+# configs [optional]
+#   Extra configs to apply to the compile step.
+#
 # deps [optional]
 #   If any deps are specified they will be inherited by the static library
 #   target.
@@ -86,6 +94,7 @@
     "$compiler_root/cc_generator.py",
     "$compiler_root/code.py",
     "$compiler_root/compiler.py",
+    "$compiler_root/cpp_bundle_generator.py",
     "$compiler_root/cpp_generator.py",
     "$compiler_root/cpp_type_generator.py",
     "$compiler_root/cpp_util.py",
@@ -122,6 +131,9 @@
   }
 
   if (bundle) {
+    assert(defined(invoker.bundle_name),
+           "\"bundle_name\" must be defined for bundles")
+
     uncompiled_sources = []
     if (defined(invoker.uncompiled_sources)) {
       uncompiled_sources = invoker.uncompiled_sources
@@ -139,6 +151,7 @@
                "--root=" + rebase_path("//", root_build_dir),
                "--destdir=" + rebase_path(root_gen_dir, root_build_dir),
                "--namespace=$root_namespace",
+               "--bundle-name=" + invoker.bundle_name,
                "--generator=cpp-bundle-schema",
                "--include-rules=$schema_include_rules",
              ] + rebase_path(invoker.sources, root_build_dir) +
@@ -147,6 +160,9 @@
   }
 
   if (bundle_registration) {
+    assert(defined(invoker.bundle_name),
+           "\"bundle_name\" must be defined for bundle registrations")
+
     uncompiled_sources = []
     if (defined(invoker.uncompiled_sources)) {
       uncompiled_sources = invoker.uncompiled_sources
@@ -154,7 +170,9 @@
 
     assert(defined(invoker.impl_dir),
            "\"impl_dir\" must be defined for the $target_name template.")
-    impl_dir = invoker.impl_dir
+
+    # Child directory inside the generated file tree.
+    gen_child_dir = rebase_path(invoker.impl_dir, "//")
 
     bundle_generator_registration_name =
         target_name + "_bundle_generator_registration"
@@ -162,15 +180,16 @@
       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",
+        "$root_gen_dir/$gen_child_dir/generated_api_registration.cc",
+        "$root_gen_dir/$gen_child_dir/generated_api_registration.h",
       ]
       args = [
                "--root=" + rebase_path("//", root_build_dir),
                "--destdir=" + rebase_path(root_gen_dir, root_build_dir),
                "--namespace=$root_namespace",
+               "--bundle-name=" + invoker.bundle_name,
                "--generator=cpp-bundle-registration",
-               "--impl-dir=" + rebase_path(impl_dir, "//"),
+               "--impl-dir=$gen_child_dir",
                "--include-rules=$schema_include_rules",
              ] + rebase_path(invoker.sources, root_build_dir) +
              rebase_path(uncompiled_sources, root_build_dir)
@@ -182,6 +201,9 @@
   lib_deps = []
   lib_public_deps = []
   lib_extra_configs = []
+  if (defined(invoker.configs)) {
+    lib_extra_configs += invoker.configs
+  }
 
   if (schemas) {
     lib_sources += get_target_outputs(":$schema_generator_name")
diff --git a/build/json_schema_bundle_compile.gypi b/build/json_schema_bundle_compile.gypi
index a302013..2101a89 100644
--- a/build/json_schema_bundle_compile.gypi
+++ b/build/json_schema_bundle_compile.gypi
@@ -18,6 +18,10 @@
     #     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".
+    #   bundle_name:
+    #     A string to prepend to generated bundle class names, so that multiple
+    #     bundle rules can be used without conflicting.  Only used with one of
+    #     the cpp-bundle generators.
     #
     # Functions and namespaces can be excluded by setting "nocompile" to true.
     # The default root path of API implementation sources is
@@ -57,6 +61,7 @@
         '--root=<(DEPTH)',
         '--destdir=<(SHARED_INTERMEDIATE_DIR)',
         '--namespace=<(root_namespace)',
+        '--bundle-name=<(bundle_name)',
         '--generator=cpp-bundle-schema',
         '--include-rules=<(schema_include_rules)',
         '<@(schema_files)',
diff --git a/build/json_schema_bundle_registration_compile.gypi b/build/json_schema_bundle_registration_compile.gypi
index 8c5af4e..ead8d48 100644
--- a/build/json_schema_bundle_registration_compile.gypi
+++ b/build/json_schema_bundle_registration_compile.gypi
@@ -15,6 +15,10 @@
     #     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".
+    #   bundle_name:
+    #     A string to prepend to generated bundle class names, so that multiple
+    #     bundle rules can be used without conflicting.  Only used with one of
+    #     the cpp-bundle generators.
     #
     # Functions and namespaces can be excluded by setting "nocompile" to true.
     'api_gen_dir': '<(DEPTH)/tools/json_schema_compiler',
@@ -52,6 +56,7 @@
         '--root=<(DEPTH)',
         '--destdir=<(SHARED_INTERMEDIATE_DIR)',
         '--namespace=<(root_namespace)',
+        '--bundle-name=<(bundle_name)',
         '--generator=cpp-bundle-registration',
         '--impl-dir=<(impl_dir_)',
         '<@(schema_files)',
diff --git a/build/json_to_struct.gypi b/build/json_to_struct.gypi
index 57271c8..09c8e3e 100644
--- a/build/json_to_struct.gypi
+++ b/build/json_to_struct.gypi
@@ -10,7 +10,8 @@
     #   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',
+    'struct_gen%': '<(struct_gen_dir)/json_to_struct.py',
+    'output_filename%': '<(RULE_INPUT_ROOT)',
   },
   'rules': [
     {
@@ -18,14 +19,15 @@
       'rule_name': 'genstaticinit',
       'extension': 'json',
       'inputs': [
+        '<(struct_gen)',
         '<(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',
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(output_filename).cc',
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(output_filename).h',
       ],
       'action': [
         'python',
@@ -35,6 +37,7 @@
         '--destdir=<(cc_dir)',
         '--namespace=<(namespace)',
         '--schema=<(schema_file)',
+        '--output=<(output_filename)',
       ],
       'message': 'Generating C++ static initializers from <(RULE_INPUT_PATH)',
       'process_outputs_as_sources': 1,
diff --git a/build/landmines.py b/build/landmines.py
index 97a250a..e9da6ba 100755
--- a/build/landmines.py
+++ b/build/landmines.py
@@ -19,18 +19,15 @@
 import logging
 import optparse
 import os
-import shutil
 import sys
 import subprocess
 import time
 
+import clobber
 import landmine_utils
 
 
-SRC_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-
-
-def get_build_dir(build_tool, is_iphone=False):
+def get_build_dir(build_tool, src_dir, is_iphone=False):
   """
   Returns output directory absolute path dependent on build and targets.
   Examples:
@@ -42,7 +39,7 @@
   """
   ret = None
   if build_tool == 'xcode':
-    ret = os.path.join(SRC_DIR, 'xcodebuild')
+    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()
@@ -50,89 +47,16 @@
         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)
+    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):
+def clobber_if_necessary(new_landmines, src_dir):
   """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'))
+  out_dir = get_build_dir(landmine_utils.builder(), src_dir)
+  landmines_path = os.path.normpath(os.path.join(src_dir, '.landmines'))
   try:
     os.makedirs(out_dir)
   except OSError as e:
@@ -150,14 +74,7 @@
       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)
+      clobber.clobber(out_dir)
 
   # Save current set of landmines for next time.
   with open(landmines_path, 'w') as f:
@@ -165,14 +82,16 @@
 
 
 def process_options():
-  """Returns a list of landmine emitting scripts."""
+  """Returns an options object containing the configuration for this script."""
   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('-d', '--src-dir',
+      help='Path of the source root dir. Overrides the default location of the '
+           'source root dir when calculating the build directory.')
   parser.add_option('-v', '--verbose', action='store_true',
       default=('LANDMINES_VERBOSE' in os.environ),
       help=('Emit some extra debugging information (default off). This option '
@@ -187,15 +106,27 @@
   logging.basicConfig(
       level=logging.DEBUG if options.verbose else logging.ERROR)
 
+  if options.src_dir:
+    if not os.path.isdir(options.src_dir):
+      parser.error('Cannot find source root dir at %s' % options.src_dir)
+    logging.debug('Overriding source root dir. Using: %s', options.src_dir)
+  else:
+    options.src_dir = \
+        os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+
+  if not options.landmine_scripts:
+    options.landmine_scripts = [os.path.join(options.src_dir, 'build',
+                                             'get_landmines.py')]
+
   extra_script = os.environ.get('EXTRA_LANDMINES_SCRIPT')
   if extra_script:
-    return options.landmine_scripts + [extra_script]
-  else:
-    return options.landmine_scripts
+    options.landmine_scripts += [extra_script]
+
+  return options
 
 
 def main():
-  landmine_scripts = process_options()
+  options = process_options()
 
   if landmine_utils.builder() in ('dump_dependency_json', 'eclipse'):
     return 0
@@ -203,11 +134,11 @@
   gyp_environment.SetEnvironment()
 
   landmines = []
-  for s in landmine_scripts:
+  for s in options.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)
+  clobber_if_necessary(landmines, options.src_dir)
 
   return 0
 
diff --git a/build/linux/BUILD.gn b/build/linux/BUILD.gn
new file mode 100644
index 0000000..a66d86c
--- /dev/null
+++ b/build/linux/BUILD.gn
@@ -0,0 +1,117 @@
+# 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.
+
+import("//build/config/features.gni")
+import("//build/config/linux/pkg_config.gni")
+import("//tools/generate_library_loader/generate_library_loader.gni")
+
+gypi_values = exec_script("//build/gypi_to_gn.py",
+                          [ rebase_path("system.gyp") ],
+                          "scope",
+                          [ "system.gyp" ])
+
+use_system_fontconfig = !is_chromecast
+
+# 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
+  }
+}
+if (use_gio) {
+  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.
+  }
+
+  # 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 = "//build/linux: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",
+  ]
+}
+
+group("fontconfig") {
+  if (use_system_fontconfig) {
+    public_configs = [ "//build/config/linux:fontconfig" ]
+  } else {
+    public_deps = [
+      "//third_party/fontconfig",
+    ]
+  }
+}
diff --git a/build/linux/OWNERS b/build/linux/OWNERS
new file mode 100644
index 0000000..4a60b79
--- /dev/null
+++ b/build/linux/OWNERS
@@ -0,0 +1,3 @@
+mmoss@chromium.org
+phajdan.jr@chromium.org
+thestig@chromium.org
diff --git a/build/linux/bin/eu-strip b/build/linux/bin/eu-strip
new file mode 100755
index 0000000..7f93eec
--- /dev/null
+++ b/build/linux/bin/eu-strip
Binary files differ
diff --git a/build/linux/dump_app_syms b/build/linux/dump_app_syms
deleted file mode 100755
index cbeb676..0000000
--- a/build/linux/dump_app_syms
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/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/dump_app_syms.py b/build/linux/dump_app_syms.py
new file mode 100644
index 0000000..c18bff7
--- /dev/null
+++ b/build/linux/dump_app_syms.py
@@ -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.
+
+# Helper script to run dump_syms on Chrome Linux executables and strip
+# them if needed.
+
+import os
+import subprocess
+import sys
+
+if len(sys.argv) != 5:
+  print "dump_app_syms.py <dump_syms_exe> <strip_binary>"
+  print "                 <binary_with_symbols> <symbols_output>"
+  sys.exit(1)
+
+dumpsyms = sys.argv[1]
+strip_binary = sys.argv[2]
+infile = sys.argv[3]
+outfile = sys.argv[4]
+
+# Dump only when the output file is out-of-date.
+if not os.path.isfile(outfile) or \
+   os.stat(outfile).st_mtime > os.stat(infile).st_mtime:
+  with open(outfile, 'w') as outfileobj:
+    subprocess.check_call([dumpsyms, '-r', infile], stdout=outfileobj)
+
+if strip_binary != '0':
+  subprocess.check_call(['strip', infile])
diff --git a/build/linux/install-chromeos-fonts.py b/build/linux/install-chromeos-fonts.py
index a24adc9..460f10d 100755
--- a/build/linux/install-chromeos-fonts.py
+++ b/build/linux/install-chromeos-fonts.py
@@ -12,10 +12,21 @@
 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)
+URL_TEMPLATE = ('https://commondatastorage.googleapis.com/chromeos-localmirror/'
+                'distfiles/%(name)s-%(version)s.tar.bz2')
+
+# Taken from the media-fonts/<name> ebuilds in chromiumos-overlay.
+SOURCES = [
+  {
+    'name': 'notofonts',
+    'version': '20150706'
+  }, {
+    'name': 'robotofonts',
+    'version': '20150625'
+  }
+]
+
+URLS = sorted([URL_TEMPLATE % d for d in SOURCES])
 FONTS_DIR = '/usr/local/share/fonts'
 
 def main(args):
@@ -36,7 +47,7 @@
   stamp = os.path.join(dest_dir, ".stamp02")
   if os.path.exists(stamp):
     with open(stamp) as s:
-      if s.read() == URL:
+      if s.read() == '\n'.join(URLS):
         print "Chrome OS fonts already up-to-date in %s." % dest_dir
         return 0
 
@@ -46,11 +57,12 @@
   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)
+  for url in URLS:
+    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:
@@ -59,7 +71,7 @@
     s.write("Script: %s\n" % __file__)
 
   with open(stamp, 'w') as s:
-    s.write(URL)
+    s.write('\n'.join(URLS))
 
   for base, dirs, files in os.walk(dest_dir):
     for dir in dirs:
diff --git a/build/linux/sysroot_scripts/install-sysroot.py b/build/linux/sysroot_scripts/install-sysroot.py
new file mode 100755
index 0000000..e922cb7
--- /dev/null
+++ b/build/linux/sysroot_scripts/install-sysroot.py
@@ -0,0 +1,210 @@
+#!/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.
+
+# Script to install a Debian Wheezy sysroot for making official Google Chrome
+# Linux builds.
+# The sysroot is needed to make Chrome work for Debian Wheezy.
+# This script can be run manually but is more often run as part of gclient
+# hooks. When run from hooks this script should be a no-op on non-linux
+# platforms.
+
+# The sysroot image could be constructed from scratch based on the current
+# state or Debian Wheezy but for consistency we currently use a pre-built root
+# image. The image will normally need to be rebuilt every time chrome's build
+# dependancies are changed.
+
+import hashlib
+import platform
+import optparse
+import os
+import re
+import shutil
+import subprocess
+import sys
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+sys.path.append(os.path.dirname(os.path.dirname(os.path.join(SCRIPT_DIR))))
+import detect_host_arch
+import gyp_chromium
+import gyp_environment
+
+
+URL_PREFIX = 'http://storage.googleapis.com'
+URL_PATH = 'chrome-linux-sysroot/toolchain'
+REVISION_AMD64 = '402274e42cb72fde4f48a4bb01664d0ad4533c69'
+REVISION_ARM = '402274e42cb72fde4f48a4bb01664d0ad4533c69'
+REVISION_I386 = '402274e42cb72fde4f48a4bb01664d0ad4533c69'
+REVISION_MIPS = '402274e42cb72fde4f48a4bb01664d0ad4533c69'
+TARBALL_AMD64 = 'debian_wheezy_amd64_sysroot.tgz'
+TARBALL_ARM = 'debian_wheezy_arm_sysroot.tgz'
+TARBALL_I386 = 'debian_wheezy_i386_sysroot.tgz'
+TARBALL_MIPS = 'debian_wheezy_mips_sysroot.tgz'
+TARBALL_AMD64_SHA1SUM = '546f211d47a6544994bb6f7cf9800c3a73a12d3a'
+TARBALL_ARM_SHA1SUM = '457ee7165526846a8bef08f64c58db994481f159'
+TARBALL_I386_SHA1SUM = '8d00eb9e60009ec23e7cb47c6ecbcf85b319e09e'
+TARBALL_MIPS_SHA1SUM = '358d8fe133575c41354fa7fe5d9c591d199f6033'
+SYSROOT_DIR_AMD64 = 'debian_wheezy_amd64-sysroot'
+SYSROOT_DIR_ARM = 'debian_wheezy_arm-sysroot'
+SYSROOT_DIR_I386 = 'debian_wheezy_i386-sysroot'
+SYSROOT_DIR_MIPS = 'debian_wheezy_mips-sysroot'
+
+valid_archs = ('arm', 'i386', 'amd64', 'mips')
+
+
+def GetSha1(filename):
+  sha1 = hashlib.sha1()
+  with open(filename, 'rb') as f:
+    while True:
+      # Read in 1mb chunks, so it doesn't all have to be loaded into memory.
+      chunk = f.read(1024*1024)
+      if not chunk:
+        break
+      sha1.update(chunk)
+  return sha1.hexdigest()
+
+
+def DetectArch(gyp_defines, is_android):
+  # Check for optional target_arch and only install for that architecture.
+  # If target_arch is not specified, then only install for the host
+  # architecture.
+  target_arch = gyp_defines.get('target_arch')
+  if target_arch == 'x64':
+    return 'amd64'
+  elif target_arch == 'ia32':
+    return 'i386'
+  elif target_arch == 'arm':
+    return 'arm'
+  elif target_arch == 'arm64':
+    return 'arm64'
+  elif target_arch == 'mipsel':
+    return 'mips'
+  elif target_arch:
+    raise Exception('Unrecognized target_arch: %s' % target_arch)
+
+  if is_android:
+    return 'arm'
+
+  # Figure out host arch using build/detect_host_arch.py and
+  # set target_arch to host arch
+  detected_host_arch = detect_host_arch.HostArch()
+  if detected_host_arch == 'x64':
+    return 'amd64'
+  elif detected_host_arch == 'ia32':
+    return 'i386'
+  elif detected_host_arch == 'arm':
+    return 'arm'
+  elif detected_host_arch == 'mips':
+    return 'mips'
+  else:
+    print "Unknown host arch: %s" % detected_host_arch
+
+  return None
+
+
+def main():
+  if options.running_as_hook and not sys.platform.startswith('linux'):
+    return 0
+
+  gyp_environment.SetEnvironment()
+  supplemental_includes = gyp_chromium.GetSupplementalFiles()
+  gyp_defines = gyp_chromium.GetGypVars(supplemental_includes)
+  is_android = gyp_defines.get('OS') == 'android'
+
+  if (options.running_as_hook and (not is_android) and
+      (gyp_defines.get('chromeos') or gyp_defines.get('use_sysroot') == '0')):
+    return 0
+
+  if options.arch:
+    target_arch = options.arch
+  else:
+    target_arch = DetectArch(gyp_defines, is_android)
+    if not target_arch:
+      print 'Unable to detect target architecture'
+      return 1
+
+  if is_android:
+    # 32-bit Android builds require a 32-bit host sysroot for the v8 snapshot.
+    if '64' not in target_arch:
+      ret = _InstallSysroot('i386')
+      if ret:
+        return ret
+    # Always need host sysroot (which we assume is x64).
+    target_arch = 'amd64'
+
+  return _InstallSysroot(target_arch)
+
+
+def _InstallSysroot(target_arch):
+  # The sysroot directory should match the one specified in build/common.gypi.
+  # TODO(thestig) Consider putting this else where to avoid having to recreate
+  # it on every build.
+  linux_dir = os.path.dirname(SCRIPT_DIR)
+  if target_arch == 'amd64':
+    sysroot = os.path.join(linux_dir, SYSROOT_DIR_AMD64)
+    tarball_filename = TARBALL_AMD64
+    tarball_sha1sum = TARBALL_AMD64_SHA1SUM
+    revision = REVISION_AMD64
+  elif target_arch == 'arm':
+    sysroot = os.path.join(linux_dir, SYSROOT_DIR_ARM)
+    tarball_filename = TARBALL_ARM
+    tarball_sha1sum = TARBALL_ARM_SHA1SUM
+    revision = REVISION_ARM
+  elif target_arch == 'i386':
+    sysroot = os.path.join(linux_dir, SYSROOT_DIR_I386)
+    tarball_filename = TARBALL_I386
+    tarball_sha1sum = TARBALL_I386_SHA1SUM
+    revision = REVISION_I386
+  elif target_arch == 'mips':
+    sysroot = os.path.join(linux_dir, SYSROOT_DIR_MIPS)
+    tarball_filename = TARBALL_MIPS
+    tarball_sha1sum = TARBALL_MIPS_SHA1SUM
+    revision = REVISION_MIPS
+  else:
+    print 'Unknown architecture: %s' % target_arch
+    assert(False)
+
+  url = '%s/%s/%s/%s' % (URL_PREFIX, URL_PATH, revision, tarball_filename)
+
+  stamp = os.path.join(sysroot, '.stamp')
+  if os.path.exists(stamp):
+    with open(stamp) as s:
+      if s.read() == url:
+        print 'Debian Wheezy %s root image already up-to-date: %s' % \
+            (target_arch, sysroot)
+        return 0
+
+  print 'Installing Debian Wheezy %s root image: %s' % (target_arch, sysroot)
+  if os.path.isdir(sysroot):
+    shutil.rmtree(sysroot)
+  os.mkdir(sysroot)
+  tarball = os.path.join(sysroot, tarball_filename)
+  print 'Downloading %s' % url
+  sys.stdout.flush()
+  sys.stderr.flush()
+  subprocess.check_call(['curl', '--fail', '-L', url, '-o', tarball])
+  sha1sum = GetSha1(tarball)
+  if sha1sum != tarball_sha1sum:
+    print 'Tarball sha1sum is wrong.'
+    print 'Expected %s, actual: %s' % (tarball_sha1sum, sha1sum)
+    return 1
+  subprocess.check_call(['tar', 'xf', tarball, '-C', sysroot])
+  os.remove(tarball)
+
+  with open(stamp, 'w') as s:
+    s.write(url)
+  return 0
+
+
+if __name__ == '__main__':
+  parser = optparse.OptionParser('usage: %prog [OPTIONS]')
+  parser.add_option('--running-as-hook', action='store_true',
+                    default=False, help='Used when running from gclient hooks.'
+                                        ' In this mode the sysroot will only '
+                                        'be installed for official Linux '
+                                        'builds or ARM Linux builds')
+  parser.add_option('--arch', type='choice', choices=valid_archs,
+                    help='Sysroot architecture: %s' % ', '.join(valid_archs))
+  options, _ = parser.parse_args()
+  sys.exit(main())
diff --git a/build/linux/sysroot_scripts/packagelist.trusty.arm b/build/linux/sysroot_scripts/packagelist.trusty.arm
new file mode 100644
index 0000000..cd4b671
--- /dev/null
+++ b/build/linux/sysroot_scripts/packagelist.trusty.arm
@@ -0,0 +1,158 @@
+main/a/alsa-lib/libasound2_1.0.27.2-3ubuntu7_armhf.deb
+main/a/alsa-lib/libasound2-dev_1.0.27.2-3ubuntu7_armhf.deb
+main/a/atk1.0/libatk1.0-0_2.10.0-2ubuntu2_armhf.deb
+main/a/atk1.0/libatk1.0-dev_2.10.0-2ubuntu2_armhf.deb
+main/a/avahi/libavahi-client3_0.6.31-4ubuntu1_armhf.deb
+main/a/avahi/libavahi-common3_0.6.31-4ubuntu1_armhf.deb
+main/c/cairo/libcairo2_1.13.0~20140204-0ubuntu1_armhf.deb
+main/c/cairo/libcairo2-dev_1.13.0~20140204-0ubuntu1_armhf.deb
+main/c/cairo/libcairo-gobject2_1.13.0~20140204-0ubuntu1_armhf.deb
+main/c/cairo/libcairo-script-interpreter2_1.13.0~20140204-0ubuntu1_armhf.deb
+main/c/cups/libcups2_1.7.2-0ubuntu1_armhf.deb
+main/c/cups/libcups2-dev_1.7.2-0ubuntu1_armhf.deb
+main/d/dbus-glib/libdbus-glib-1-2_0.100.2-1_armhf.deb
+main/d/dbus/libdbus-1-3_1.6.18-0ubuntu4_armhf.deb
+main/d/dbus/libdbus-1-dev_1.6.18-0ubuntu4_armhf.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.9-3ubuntu1_armhf.deb
+main/e/e2fsprogs/libcomerr2_1.42.9-3ubuntu1_armhf.deb
+main/e/eglibc/libc6_2.19-0ubuntu6_armhf.deb
+main/e/eglibc/libc6-dev_2.19-0ubuntu6_armhf.deb
+main/e/elfutils/libelf1_0.158-0ubuntu5_armhf.deb
+main/e/elfutils/libelf-dev_0.158-0ubuntu5_armhf.deb
+main/e/expat/libexpat1_2.1.0-4ubuntu1_armhf.deb
+main/e/expat/libexpat1-dev_2.1.0-4ubuntu1_armhf.deb
+main/f/fontconfig/libfontconfig1_2.11.0-0ubuntu4_armhf.deb
+main/f/fontconfig/libfontconfig1-dev_2.11.0-0ubuntu4_armhf.deb
+main/f/freetype/libfreetype6_2.5.2-1ubuntu2_armhf.deb
+main/f/freetype/libfreetype6-dev_2.5.2-1ubuntu2_armhf.deb
+main/g/gcc-4.8/gcc-4.8_4.8.2-19ubuntu1_armhf.deb
+main/g/gcc-4.8/libgomp1_4.8.2-19ubuntu1_armhf.deb
+main/g/gcc-4.8/libstdc++-4.8-dev_4.8.2-19ubuntu1_armhf.deb
+main/g/gcc-4.8/libstdc++6_4.8.2-19ubuntu1_armhf.deb
+main/g/gccgo-4.9/libgcc1_4.9-20140406-0ubuntu1_armhf.deb
+main/g/gconf/libgconf2-4_3.2.6-0ubuntu2_armhf.deb
+main/g/gconf/libgconf-2-4_3.2.6-0ubuntu2_armhf.deb
+main/g/gconf/libgconf2-dev_3.2.6-0ubuntu2_armhf.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.30.7-0ubuntu1_armhf.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.30.7-0ubuntu1_armhf.deb
+main/g/glib2.0/libglib2.0-0_2.40.0-2_armhf.deb
+main/g/glib2.0/libglib2.0-dev_2.40.0-2_armhf.deb
+main/g/gnutls26/libgnutls26_2.12.23-12ubuntu2_armhf.deb
+main/g/gnutls26/libgnutls-dev_2.12.23-12ubuntu2_armhf.deb
+main/g/gnutls26/libgnutls-openssl27_2.12.23-12ubuntu2_armhf.deb
+main/g/gnutls26/libgnutlsxx27_2.12.23-12ubuntu2_armhf.deb
+main/g/gtk+2.0/libgtk2.0-0_2.24.23-0ubuntu1_armhf.deb
+main/g/gtk+2.0/libgtk2.0-dev_2.24.23-0ubuntu1_armhf.deb
+main/k/keyutils/libkeyutils1_1.5.6-1_armhf.deb
+main/k/krb5/krb5-multidev_1.12+dfsg-2ubuntu4_armhf.deb
+main/k/krb5/libgssapi-krb5-2_1.12+dfsg-2ubuntu4_armhf.deb
+main/k/krb5/libgssrpc4_1.12+dfsg-2ubuntu4_armhf.deb
+main/k/krb5/libk5crypto3_1.12+dfsg-2ubuntu4_armhf.deb
+main/k/krb5/libkadm5clnt-mit9_1.12+dfsg-2ubuntu4_armhf.deb
+main/k/krb5/libkadm5srv-mit9_1.12+dfsg-2ubuntu4_armhf.deb
+main/k/krb5/libkdb5-7_1.12+dfsg-2ubuntu4_armhf.deb
+main/k/krb5/libkrb5-3_1.12+dfsg-2ubuntu4_armhf.deb
+main/k/krb5/libkrb5-dev_1.12+dfsg-2ubuntu4_armhf.deb
+main/k/krb5/libkrb5support0_1.12+dfsg-2ubuntu4_armhf.deb
+main/libc/libcap2/libcap2_2.24-0ubuntu2_armhf.deb
+main/libc/libcap2/libcap-dev_2.24-0ubuntu2_armhf.deb
+main/libd/libdrm/libdrm2_2.4.52-1_armhf.deb
+main/libe/libexif/libexif12_0.6.21-1ubuntu1_armhf.deb
+main/libe/libexif/libexif-dev_0.6.21-1ubuntu1_armhf.deb
+main/libf/libffi/libffi6_3.1~rc1+r3.0.13-12_armhf.deb
+main/libg/libgcrypt11/libgcrypt11_1.5.3-2ubuntu4_armhf.deb
+main/libg/libgcrypt11/libgcrypt11-dev_1.5.3-2ubuntu4_armhf.deb
+main/libg/libgnome-keyring/libgnome-keyring0_3.8.0-2_armhf.deb
+main/libg/libgnome-keyring/libgnome-keyring-dev_3.8.0-2_armhf.deb
+main/libg/libgpg-error/libgpg-error0_1.12-0.2ubuntu1_armhf.deb
+main/libg/libgpg-error/libgpg-error-dev_1.12-0.2ubuntu1_armhf.deb
+main/libn/libnss-db/libnss-db_2.2.3pre1-5build3_armhf.deb
+main/libp/libp11/libp11-2_0.2.8-3ubuntu1_armhf.deb
+main/libp/libpng/libpng12-0_1.2.50-1ubuntu2_armhf.deb
+main/libp/libpng/libpng12-dev_1.2.50-1ubuntu2_armhf.deb
+main/libs/libselinux/libselinux1_2.2.2-1_armhf.deb
+main/libt/libtasn1-6/libtasn1-6_3.4-3_armhf.deb
+main/libx/libx11/libx11-6_1.6.2-1ubuntu2_armhf.deb
+main/libx/libx11/libx11-dev_1.6.2-1ubuntu2_armhf.deb
+main/libx/libx11/libx11-xcb1_1.6.2-1ubuntu2_armhf.deb
+main/libx/libxau/libxau6_1.0.8-1_armhf.deb
+main/libx/libxau/libxau-dev_1.0.8-1_armhf.deb
+main/libx/libxcb/libxcb1_1.10-2ubuntu1_armhf.deb
+main/libx/libxcb/libxcb1-dev_1.10-2ubuntu1_armhf.deb
+main/libx/libxcb/libxcb-glx0_1.10-2ubuntu1_armhf.deb
+main/libx/libxcb/libxcb-render0_1.10-2ubuntu1_armhf.deb
+main/libx/libxcb/libxcb-render0-dev_1.10-2ubuntu1_armhf.deb
+main/libx/libxcb/libxcb-shm0_1.10-2ubuntu1_armhf.deb
+main/libx/libxcb/libxcb-shm0-dev_1.10-2ubuntu1_armhf.deb
+main/libx/libxcomposite/libxcomposite1_0.4.4-1_armhf.deb
+main/libx/libxcomposite/libxcomposite-dev_0.4.4-1_armhf.deb
+main/libx/libxcursor/libxcursor1_1.1.14-1_armhf.deb
+main/libx/libxcursor/libxcursor-dev_1.1.14-1_armhf.deb
+main/libx/libxdamage/libxdamage1_1.1.4-1ubuntu1_armhf.deb
+main/libx/libxdamage/libxdamage-dev_1.1.4-1ubuntu1_armhf.deb
+main/libx/libxdmcp/libxdmcp6_1.1.1-1_armhf.deb
+main/libx/libxext/libxext6_1.3.2-1_armhf.deb
+main/libx/libxext/libxext-dev_1.3.2-1_armhf.deb
+main/libx/libxfixes/libxfixes3_5.0.1-1ubuntu1_armhf.deb
+main/libx/libxfixes/libxfixes-dev_5.0.1-1ubuntu1_armhf.deb
+main/libx/libxi/libxi6_1.7.1.901-1ubuntu1_armhf.deb
+main/libx/libxi/libxi-dev_1.7.1.901-1ubuntu1_armhf.deb
+main/libx/libxinerama/libxinerama1_1.1.3-1_armhf.deb
+main/libx/libxinerama/libxinerama-dev_1.1.3-1_armhf.deb
+main/libx/libxrandr/libxrandr2_1.4.2-1_armhf.deb
+main/libx/libxrandr/libxrandr-dev_1.4.2-1_armhf.deb
+main/libx/libxrender/libxrender1_0.9.8-1_armhf.deb
+main/libx/libxrender/libxrender-dev_0.9.8-1_armhf.deb
+main/libx/libxss/libxss1_1.2.2-1_armhf.deb
+main/libx/libxss/libxss-dev_1.2.2-1_armhf.deb
+main/libx/libxt/libxt6_1.1.4-1_armhf.deb
+main/libx/libxt/libxt-dev_1.1.4-1_armhf.deb
+main/libx/libxtst/libxtst6_1.2.2-1_armhf.deb
+main/libx/libxtst/libxtst-dev_1.2.2-1_armhf.deb
+main/libx/libxxf86vm/libxxf86vm1_1.1.3-1_armhf.deb
+main/l/linux/linux-libc-dev_3.13.0-24.46_armhf.deb
+main/m/mesa/libgl1-mesa-dev_10.1.0-4ubuntu5_armhf.deb
+main/m/mesa/libgl1-mesa-glx_10.1.0-4ubuntu5_armhf.deb
+main/m/mesa/libglapi-mesa_10.1.0-4ubuntu5_armhf.deb
+main/m/mesa/mesa-common-dev_10.1.0-4ubuntu5_armhf.deb
+main/n/nspr/libnspr4_4.10.2-1ubuntu1_armhf.deb
+main/n/nspr/libnspr4-dev_4.10.2-1ubuntu1_armhf.deb
+main/n/nss/libnss3_3.15.4-1ubuntu7_armhf.deb
+main/n/nss/libnss3-dev_3.15.4-1ubuntu7_armhf.deb
+main/o/openssl/libssl1.0.0_1.0.1f-1ubuntu2_armhf.deb
+main/o/openssl/libssl-dev_1.0.1f-1ubuntu2_armhf.deb
+main/o/orbit2/liborbit2_2.14.19-0.3_armhf.deb
+main/p/p11-kit/libp11-kit0_0.20.2-2ubuntu2_armhf.deb
+main/p/pam/libpam0g_1.1.8-1ubuntu2_armhf.deb
+main/p/pam/libpam0g-dev_1.1.8-1ubuntu2_armhf.deb
+main/p/pango1.0/libpango-1.0-0_1.36.3-1ubuntu1_armhf.deb
+main/p/pango1.0/libpango1.0-dev_1.36.3-1ubuntu1_armhf.deb
+main/p/pango1.0/libpangocairo-1.0-0_1.36.3-1ubuntu1_armhf.deb
+main/p/pango1.0/libpangoft2-1.0-0_1.36.3-1ubuntu1_armhf.deb
+main/p/pango1.0/libpangoxft-1.0-0_1.36.3-1ubuntu1_armhf.deb
+main/p/pciutils/libpci3_3.2.1-1ubuntu5_armhf.deb
+main/p/pciutils/libpci-dev_3.2.1-1ubuntu5_armhf.deb
+main/p/pcre3/libpcre3_8.31-2ubuntu2_armhf.deb
+main/p/pcre3/libpcre3-dev_8.31-2ubuntu2_armhf.deb
+main/p/pcre3/libpcrecpp0_8.31-2ubuntu2_armhf.deb
+main/p/pixman/libpixman-1-0_0.30.2-2ubuntu1_armhf.deb
+main/p/pixman/libpixman-1-dev_0.30.2-2ubuntu1_armhf.deb
+main/p/pulseaudio/libpulse0_4.0-0ubuntu11_armhf.deb
+main/p/pulseaudio/libpulse-dev_4.0-0ubuntu11_armhf.deb
+main/p/pulseaudio/libpulse-mainloop-glib0_4.0-0ubuntu11_armhf.deb
+main/s/speech-dispatcher/libspeechd2_0.8-5ubuntu1_armhf.deb
+main/s/speech-dispatcher/libspeechd-dev_0.8-5ubuntu1_armhf.deb
+main/s/speech-dispatcher/speech-dispatcher_0.8-5ubuntu1_armhf.deb
+main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
+main/x/x11proto-core/x11proto-core-dev_7.0.24-1_all.deb
+main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
+main/x/x11proto-fixes/x11proto-fixes-dev_5.0-2ubuntu2_all.deb
+main/x/x11proto-input/x11proto-input-dev_2.3-1_all.deb
+main/x/x11proto-kb/x11proto-kb-dev_1.0.6-2_all.deb
+main/x/x11proto-randr/x11proto-randr-dev_1.4.0+git20120101.is.really.1.4.0-0ubuntu1_all.deb
+main/x/x11proto-record/x11proto-record-dev_1.14.2-1_all.deb
+main/x/x11proto-render/x11proto-render-dev_0.11.1-2_all.deb
+main/x/x11proto-scrnsaver/x11proto-scrnsaver-dev_1.2.2-1_all.deb
+main/x/x11proto-xext/x11proto-xext-dev_7.3.0-1_all.deb
+main/z/zlib/zlib1g_1.2.8.dfsg-1ubuntu1_armhf.deb
+main/z/zlib/zlib1g-dev_1.2.8.dfsg-1ubuntu1_armhf.deb
diff --git a/build/linux/sysroot_scripts/packagelist.wheezy.amd64 b/build/linux/sysroot_scripts/packagelist.wheezy.amd64
new file mode 100644
index 0000000..dba67e3
--- /dev/null
+++ b/build/linux/sysroot_scripts/packagelist.wheezy.amd64
@@ -0,0 +1,163 @@
+main/a/alsa-lib/libasound2_1.0.25-4_amd64.deb
+main/a/alsa-lib/libasound2-dev_1.0.25-4_amd64.deb
+main/a/atk1.0/libatk1.0-0_2.4.0-2_amd64.deb
+main/a/atk1.0/libatk1.0-dev_2.4.0-2_amd64.deb
+main/a/attr/libattr1_2.4.46-8_amd64.deb
+main/a/avahi/libavahi-client3_0.6.31-2_amd64.deb
+main/a/avahi/libavahi-common3_0.6.31-2_amd64.deb
+main/c/cairo/libcairo2_1.12.2-3_amd64.deb
+main/c/cairo/libcairo2-dev_1.12.2-3_amd64.deb
+main/c/cairo/libcairo-gobject2_1.12.2-3_amd64.deb
+main/c/cairo/libcairo-script-interpreter2_1.12.2-3_amd64.deb
+main/c/cups/libcups2_1.5.3-5+deb7u6_amd64.deb
+main/c/cups/libcups2-dev_1.5.3-5+deb7u6_amd64.deb
+main/d/dbus-glib/libdbus-glib-1-2_0.100.2-1_amd64.deb
+main/d/dbus/libdbus-1-3_1.6.8-1+deb7u6_amd64.deb
+main/d/dbus/libdbus-1-dev_1.6.8-1+deb7u6_amd64.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.5-1.1+deb7u1_amd64.deb
+main/e/e2fsprogs/libcomerr2_1.42.5-1.1+deb7u1_amd64.deb
+main/e/eglibc/libc6_2.13-38+deb7u8_amd64.deb
+main/e/eglibc/libc6-dev_2.13-38+deb7u8_amd64.deb
+main/e/elfutils/libelf1_0.152-1+wheezy1_amd64.deb
+main/e/elfutils/libelf-dev_0.152-1+wheezy1_amd64.deb
+main/e/expat/libexpat1_2.1.0-1+deb7u2_amd64.deb
+main/e/expat/libexpat1-dev_2.1.0-1+deb7u2_amd64.deb
+main/f/fontconfig/libfontconfig1_2.9.0-7.1_amd64.deb
+main/f/fontconfig/libfontconfig1-dev_2.9.0-7.1_amd64.deb
+main/f/freetype/libfreetype6_2.4.9-1.1+deb7u1_amd64.deb
+main/f/freetype/libfreetype6-dev_2.4.9-1.1+deb7u1_amd64.deb
+main/g/gcc-4.6/gcc-4.6_4.6.3-14_amd64.deb
+main/g/gcc-4.6/libstdc++6-4.6-dev_4.6.3-14_amd64.deb
+main/g/gcc-4.7/libgcc1_4.7.2-5_amd64.deb
+main/g/gcc-4.7/libgomp1_4.7.2-5_amd64.deb
+main/g/gcc-4.7/libquadmath0_4.7.2-5_amd64.deb
+main/g/gcc-4.7/libstdc++6_4.7.2-5_amd64.deb
+main/g/gconf/libgconf-2-4_3.2.5-1+build1_amd64.deb
+main/g/gconf/libgconf2-4_3.2.5-1+build1_amd64.deb
+main/g/gconf/libgconf2-dev_3.2.5-1+build1_amd64.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.26.1-1+deb7u1_amd64.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.26.1-1+deb7u1_amd64.deb
+main/g/glib2.0/libglib2.0-0_2.33.12+really2.32.4-5_amd64.deb
+main/g/glib2.0/libglib2.0-dev_2.33.12+really2.32.4-5_amd64.deb
+main/g/gnutls26/libgnutls26_2.12.20-8+deb7u3_amd64.deb
+main/g/gnutls26/libgnutls-dev_2.12.20-8+deb7u3_amd64.deb
+main/g/gnutls26/libgnutls-openssl27_2.12.20-8+deb7u3_amd64.deb
+main/g/gnutls26/libgnutlsxx27_2.12.20-8+deb7u3_amd64.deb
+main/g/gtk+2.0/libgtk2.0-0_2.24.10-2_amd64.deb
+main/g/gtk+2.0/libgtk2.0-dev_2.24.10-2_amd64.deb
+main/k/keyutils/libkeyutils1_1.5.5-3+deb7u1_amd64.deb
+main/k/krb5/krb5-multidev_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/k/krb5/libgssapi-krb5-2_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/k/krb5/libgssrpc4_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/k/krb5/libk5crypto3_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/k/krb5/libkadm5clnt-mit8_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/k/krb5/libkadm5srv-mit8_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/k/krb5/libkdb5-6_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/k/krb5/libkrb5-3_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/k/krb5/libkrb5-dev_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/k/krb5/libkrb5support0_1.10.1+dfsg-5+deb7u3_amd64.deb
+main/libc/libcap2/libcap2_2.22-1.2_amd64.deb
+main/libc/libcap2/libcap-dev_2.22-1.2_amd64.deb
+main/libd/libdrm/libdrm2_2.4.40-1~deb7u2_amd64.deb
+main/libd/libdrm/libdrm-dev_2.4.40-1~deb7u2_amd64.deb
+main/libd/libdrm/libdrm-intel1_2.4.40-1~deb7u2_amd64.deb
+main/libd/libdrm/libdrm-nouveau1a_2.4.40-1~deb7u2_amd64.deb
+main/libd/libdrm/libdrm-radeon1_2.4.40-1~deb7u2_amd64.deb
+main/libd/libdrm/libkms1_2.4.40-1~deb7u2_amd64.deb
+main/libe/libexif/libexif12_0.6.20-3_amd64.deb
+main/libe/libexif/libexif-dev_0.6.20-3_amd64.deb
+main/libf/libffi/libffi5_3.0.10-3_amd64.deb
+main/libf/libffi/libffi-dev_3.0.10-3_amd64.deb
+main/libg/libgcrypt11/libgcrypt11_1.5.0-5+deb7u3_amd64.deb
+main/libg/libgcrypt11/libgcrypt11-dev_1.5.0-5+deb7u3_amd64.deb
+main/libg/libgnome-keyring/libgnome-keyring0_3.4.1-1_amd64.deb
+main/libg/libgnome-keyring/libgnome-keyring-dev_3.4.1-1_amd64.deb
+main/libg/libgpg-error/libgpg-error0_1.10-3.1_amd64.deb
+main/libg/libgpg-error/libgpg-error-dev_1.10-3.1_amd64.deb
+main/libn/libnss-db/libnss-db_2.2.3pre1-4_amd64.deb
+main/libp/libp11/libp11-2_0.2.8-2_amd64.deb
+main/libp/libpng/libpng12-0_1.2.49-1_amd64.deb
+main/libp/libpng/libpng12-dev_1.2.49-1_amd64.deb
+main/libs/libselinux/libselinux1_2.1.9-5_amd64.deb
+main/libt/libtasn1-3/libtasn1-3_2.13-2+deb7u2_amd64.deb
+main/libx/libx11/libx11-6_1.5.0-1+deb7u2_amd64.deb
+main/libx/libx11/libx11-dev_1.5.0-1+deb7u2_amd64.deb
+main/libx/libx11/libx11-xcb1_1.5.0-1+deb7u2_amd64.deb
+main/libx/libxau/libxau6_1.0.7-1_amd64.deb
+main/libx/libxau/libxau-dev_1.0.7-1_amd64.deb
+main/libx/libxcb/libxcb1_1.8.1-2+deb7u1_amd64.deb
+main/libx/libxcb/libxcb1-dev_1.8.1-2+deb7u1_amd64.deb
+main/libx/libxcb/libxcb-glx0_1.8.1-2+deb7u1_amd64.deb
+main/libx/libxcb/libxcb-render0_1.8.1-2+deb7u1_amd64.deb
+main/libx/libxcb/libxcb-render0-dev_1.8.1-2+deb7u1_amd64.deb
+main/libx/libxcb/libxcb-shm0_1.8.1-2+deb7u1_amd64.deb
+main/libx/libxcb/libxcb-shm0-dev_1.8.1-2+deb7u1_amd64.deb
+main/libx/libxcomposite/libxcomposite1_0.4.3-2_amd64.deb
+main/libx/libxcomposite/libxcomposite-dev_0.4.3-2_amd64.deb
+main/libx/libxcursor/libxcursor1_1.1.13-1+deb7u1_amd64.deb
+main/libx/libxcursor/libxcursor-dev_1.1.13-1+deb7u1_amd64.deb
+main/libx/libxdamage/libxdamage1_1.1.3-2_amd64.deb
+main/libx/libxdamage/libxdamage-dev_1.1.3-2_amd64.deb
+main/libx/libxdmcp/libxdmcp6_1.1.1-1_amd64.deb
+main/libx/libxext/libxext6_1.3.1-2+deb7u1_amd64.deb
+main/libx/libxext/libxext-dev_1.3.1-2+deb7u1_amd64.deb
+main/libx/libxfixes/libxfixes3_5.0-4+deb7u1_amd64.deb
+main/libx/libxfixes/libxfixes-dev_5.0-4+deb7u1_amd64.deb
+main/libx/libxi/libxi6_1.6.1-1+deb7u1_amd64.deb
+main/libx/libxi/libxi-dev_1.6.1-1+deb7u1_amd64.deb
+main/libx/libxinerama/libxinerama1_1.1.2-1+deb7u1_amd64.deb
+main/libx/libxinerama/libxinerama-dev_1.1.2-1+deb7u1_amd64.deb
+main/libx/libxrandr/libxrandr2_1.3.2-2+deb7u1_amd64.deb
+main/libx/libxrandr/libxrandr-dev_1.3.2-2+deb7u1_amd64.deb
+main/libx/libxrender/libxrender1_0.9.7-1+deb7u2_amd64.deb
+main/libx/libxrender/libxrender-dev_0.9.7-1+deb7u2_amd64.deb
+main/libx/libxss/libxss1_1.2.2-1_amd64.deb
+main/libx/libxss/libxss-dev_1.2.2-1_amd64.deb
+main/libx/libxt/libxt6_1.1.3-1+deb7u1_amd64.deb
+main/libx/libxt/libxt-dev_1.1.3-1+deb7u1_amd64.deb
+main/libx/libxtst/libxtst6_1.2.1-1+deb7u1_amd64.deb
+main/libx/libxtst/libxtst-dev_1.2.1-1+deb7u1_amd64.deb
+main/libx/libxxf86vm/libxxf86vm1_1.1.2-1+deb7u1_amd64.deb
+main/l/linux/linux-libc-dev_3.2.68-1+deb7u3_amd64.deb
+main/m/mesa/libgl1-mesa-dev_8.0.5-4+deb7u2_amd64.deb
+main/m/mesa/libgl1-mesa-glx_8.0.5-4+deb7u2_amd64.deb
+main/m/mesa/libglapi-mesa_8.0.5-4+deb7u2_amd64.deb
+main/m/mesa/mesa-common-dev_8.0.5-4+deb7u2_amd64.deb
+main/n/nspr/libnspr4_4.9.2-1+deb7u2_amd64.deb
+main/n/nspr/libnspr4-dev_4.9.2-1+deb7u2_amd64.deb
+main/n/nss/libnss3_3.14.5-1+deb7u5_amd64.deb
+main/n/nss/libnss3-dev_3.14.5-1+deb7u5_amd64.deb
+main/o/openssl/libssl1.0.0_1.0.1e-2+deb7u17_amd64.deb
+main/o/openssl/libssl-dev_1.0.1e-2+deb7u17_amd64.deb
+main/o/orbit2/liborbit2_2.14.19-0.1_amd64.deb
+main/p/p11-kit/libp11-kit0_0.12-3_amd64.deb
+main/p/pam/libpam0g_1.1.3-7.1_amd64.deb
+main/p/pam/libpam0g-dev_1.1.3-7.1_amd64.deb
+main/p/pango1.0/libpango1.0-0_1.30.0-1_amd64.deb
+main/p/pango1.0/libpango1.0-dev_1.30.0-1_amd64.deb
+main/p/pciutils/libpci3_3.1.9-6_amd64.deb
+main/p/pciutils/libpci-dev_3.1.9-6_amd64.deb
+main/p/pcre3/libpcre3_8.30-5_amd64.deb
+main/p/pcre3/libpcre3-dev_8.30-5_amd64.deb
+main/p/pcre3/libpcrecpp0_8.30-5_amd64.deb
+main/p/pixman/libpixman-1-0_0.26.0-4+deb7u1_amd64.deb
+main/p/pixman/libpixman-1-dev_0.26.0-4+deb7u1_amd64.deb
+main/p/pulseaudio/libpulse0_2.0-6.1_amd64.deb
+main/p/pulseaudio/libpulse-dev_2.0-6.1_amd64.deb
+main/p/pulseaudio/libpulse-mainloop-glib0_2.0-6.1_amd64.deb
+main/s/speech-dispatcher/libspeechd2_0.7.1-6.2_amd64.deb
+main/s/speech-dispatcher/libspeechd-dev_0.7.1-6.2_amd64.deb
+main/s/speech-dispatcher/speech-dispatcher_0.7.1-6.2_amd64.deb
+main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
+main/x/x11proto-core/x11proto-core-dev_7.0.23-1_all.deb
+main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
+main/x/x11proto-fixes/x11proto-fixes-dev_5.0-2_all.deb
+main/x/x11proto-input/x11proto-input-dev_2.2-1_all.deb
+main/x/x11proto-kb/x11proto-kb-dev_1.0.6-2_all.deb
+main/x/x11proto-randr/x11proto-randr-dev_1.3.2-2_all.deb
+main/x/x11proto-record/x11proto-record-dev_1.14.2-1_all.deb
+main/x/x11proto-render/x11proto-render-dev_0.11.1-2_all.deb
+main/x/x11proto-scrnsaver/x11proto-scrnsaver-dev_1.2.2-1_all.deb
+main/x/x11proto-xext/x11proto-xext-dev_7.2.1-1_all.deb
+main/z/zlib/zlib1g_1.2.7.dfsg-13_amd64.deb
+main/z/zlib/zlib1g-dev_1.2.7.dfsg-13_amd64.deb
diff --git a/build/linux/sysroot_scripts/packagelist.wheezy.arm b/build/linux/sysroot_scripts/packagelist.wheezy.arm
new file mode 100644
index 0000000..a643196
--- /dev/null
+++ b/build/linux/sysroot_scripts/packagelist.wheezy.arm
@@ -0,0 +1,162 @@
+main/a/alsa-lib/libasound2_1.0.25-4_armhf.deb
+main/a/alsa-lib/libasound2-dev_1.0.25-4_armhf.deb
+main/a/atk1.0/libatk1.0-0_2.4.0-2_armhf.deb
+main/a/atk1.0/libatk1.0-dev_2.4.0-2_armhf.deb
+main/a/attr/libattr1_2.4.46-8_armhf.deb
+main/a/avahi/libavahi-client3_0.6.31-2_armhf.deb
+main/a/avahi/libavahi-common3_0.6.31-2_armhf.deb
+main/c/cairo/libcairo2_1.12.2-3_armhf.deb
+main/c/cairo/libcairo2-dev_1.12.2-3_armhf.deb
+main/c/cairo/libcairo-gobject2_1.12.2-3_armhf.deb
+main/c/cairo/libcairo-script-interpreter2_1.12.2-3_armhf.deb
+main/c/cups/libcups2_1.5.3-5+deb7u6_armhf.deb
+main/c/cups/libcups2-dev_1.5.3-5+deb7u6_armhf.deb
+main/d/dbus-glib/libdbus-glib-1-2_0.100.2-1_armhf.deb
+main/d/dbus/libdbus-1-3_1.6.8-1+deb7u6_armhf.deb
+main/d/dbus/libdbus-1-dev_1.6.8-1+deb7u6_armhf.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.5-1.1+deb7u1_armhf.deb
+main/e/e2fsprogs/libcomerr2_1.42.5-1.1+deb7u1_armhf.deb
+main/e/eglibc/libc6_2.13-38+deb7u8_armhf.deb
+main/e/eglibc/libc6-dev_2.13-38+deb7u8_armhf.deb
+main/e/elfutils/libelf1_0.152-1+wheezy1_armhf.deb
+main/e/elfutils/libelf-dev_0.152-1+wheezy1_armhf.deb
+main/e/expat/libexpat1_2.1.0-1+deb7u2_armhf.deb
+main/e/expat/libexpat1-dev_2.1.0-1+deb7u2_armhf.deb
+main/f/fontconfig/libfontconfig1_2.9.0-7.1_armhf.deb
+main/f/fontconfig/libfontconfig1-dev_2.9.0-7.1_armhf.deb
+main/f/freetype/libfreetype6_2.4.9-1.1+deb7u1_armhf.deb
+main/f/freetype/libfreetype6-dev_2.4.9-1.1+deb7u1_armhf.deb
+main/g/gcc-4.6/gcc-4.6_4.6.3-14_armhf.deb
+main/g/gcc-4.6/libstdc++6-4.6-dev_4.6.3-14_armhf.deb
+main/g/gcc-4.7/libgcc1_4.7.2-5_armhf.deb
+main/g/gcc-4.7/libgomp1_4.7.2-5_armhf.deb
+main/g/gcc-4.7/libstdc++6_4.7.2-5_armhf.deb
+main/g/gconf/libgconf2-4_3.2.5-1+build1_armhf.deb
+main/g/gconf/libgconf-2-4_3.2.5-1+build1_armhf.deb
+main/g/gconf/libgconf2-dev_3.2.5-1+build1_armhf.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.26.1-1+deb7u1_armhf.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.26.1-1+deb7u1_armhf.deb
+main/g/glib2.0/libglib2.0-0_2.33.12+really2.32.4-5_armhf.deb
+main/g/glib2.0/libglib2.0-dev_2.33.12+really2.32.4-5_armhf.deb
+main/g/gnutls26/libgnutls26_2.12.20-8+deb7u3_armhf.deb
+main/g/gnutls26/libgnutls-dev_2.12.20-8+deb7u3_armhf.deb
+main/g/gnutls26/libgnutls-openssl27_2.12.20-8+deb7u3_armhf.deb
+main/g/gnutls26/libgnutlsxx27_2.12.20-8+deb7u3_armhf.deb
+main/g/gtk+2.0/libgtk2.0-0_2.24.10-2_armhf.deb
+main/g/gtk+2.0/libgtk2.0-dev_2.24.10-2_armhf.deb
+main/k/keyutils/libkeyutils1_1.5.5-3+deb7u1_armhf.deb
+main/k/krb5/krb5-multidev_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/k/krb5/libgssapi-krb5-2_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/k/krb5/libgssrpc4_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/k/krb5/libk5crypto3_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/k/krb5/libkadm5clnt-mit8_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/k/krb5/libkadm5srv-mit8_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/k/krb5/libkdb5-6_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/k/krb5/libkrb5-3_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/k/krb5/libkrb5-dev_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/k/krb5/libkrb5support0_1.10.1+dfsg-5+deb7u3_armhf.deb
+main/libc/libcap2/libcap2_2.22-1.2_armhf.deb
+main/libc/libcap2/libcap-dev_2.22-1.2_armhf.deb
+main/libd/libdrm/libdrm2_2.4.40-1~deb7u2_armhf.deb
+main/libd/libdrm/libdrm-dev_2.4.40-1~deb7u2_armhf.deb
+main/libd/libdrm/libdrm-nouveau1a_2.4.40-1~deb7u2_armhf.deb
+main/libd/libdrm/libdrm-omap1_2.4.40-1~deb7u2_armhf.deb
+main/libd/libdrm/libdrm-radeon1_2.4.40-1~deb7u2_armhf.deb
+main/libd/libdrm/libkms1_2.4.40-1~deb7u2_armhf.deb
+main/libe/libexif/libexif12_0.6.20-3_armhf.deb
+main/libe/libexif/libexif-dev_0.6.20-3_armhf.deb
+main/libf/libffi/libffi5_3.0.10-3+b1_armhf.deb
+main/libf/libffi/libffi-dev_3.0.10-3+b1_armhf.deb
+main/libg/libgcrypt11/libgcrypt11_1.5.0-5+deb7u3_armhf.deb
+main/libg/libgcrypt11/libgcrypt11-dev_1.5.0-5+deb7u3_armhf.deb
+main/libg/libgnome-keyring/libgnome-keyring0_3.4.1-1_armhf.deb
+main/libg/libgnome-keyring/libgnome-keyring-dev_3.4.1-1_armhf.deb
+main/libg/libgpg-error/libgpg-error0_1.10-3.1_armhf.deb
+main/libg/libgpg-error/libgpg-error-dev_1.10-3.1_armhf.deb
+main/libn/libnss-db/libnss-db_2.2.3pre1-4_armhf.deb
+main/libp/libp11/libp11-2_0.2.8-2_armhf.deb
+main/libp/libpng/libpng12-0_1.2.49-1_armhf.deb
+main/libp/libpng/libpng12-dev_1.2.49-1_armhf.deb
+main/libs/libselinux/libselinux1_2.1.9-5_armhf.deb
+main/libt/libtasn1-3/libtasn1-3_2.13-2+deb7u2_armhf.deb
+main/libx/libx11/libx11-6_1.5.0-1+deb7u2_armhf.deb
+main/libx/libx11/libx11-dev_1.5.0-1+deb7u2_armhf.deb
+main/libx/libx11/libx11-xcb1_1.5.0-1+deb7u2_armhf.deb
+main/libx/libxau/libxau6_1.0.7-1_armhf.deb
+main/libx/libxau/libxau-dev_1.0.7-1_armhf.deb
+main/libx/libxcb/libxcb1_1.8.1-2+deb7u1_armhf.deb
+main/libx/libxcb/libxcb1-dev_1.8.1-2+deb7u1_armhf.deb
+main/libx/libxcb/libxcb-glx0_1.8.1-2+deb7u1_armhf.deb
+main/libx/libxcb/libxcb-render0_1.8.1-2+deb7u1_armhf.deb
+main/libx/libxcb/libxcb-render0-dev_1.8.1-2+deb7u1_armhf.deb
+main/libx/libxcb/libxcb-shm0_1.8.1-2+deb7u1_armhf.deb
+main/libx/libxcb/libxcb-shm0-dev_1.8.1-2+deb7u1_armhf.deb
+main/libx/libxcomposite/libxcomposite1_0.4.3-2+b1_armhf.deb
+main/libx/libxcomposite/libxcomposite-dev_0.4.3-2+b1_armhf.deb
+main/libx/libxcursor/libxcursor1_1.1.13-1+deb7u1_armhf.deb
+main/libx/libxcursor/libxcursor-dev_1.1.13-1+deb7u1_armhf.deb
+main/libx/libxdamage/libxdamage1_1.1.3-2+b1_armhf.deb
+main/libx/libxdamage/libxdamage-dev_1.1.3-2+b1_armhf.deb
+main/libx/libxdmcp/libxdmcp6_1.1.1-1_armhf.deb
+main/libx/libxext/libxext6_1.3.1-2+deb7u1_armhf.deb
+main/libx/libxext/libxext-dev_1.3.1-2+deb7u1_armhf.deb
+main/libx/libxfixes/libxfixes3_5.0-4+deb7u1_armhf.deb
+main/libx/libxfixes/libxfixes-dev_5.0-4+deb7u1_armhf.deb
+main/libx/libxi/libxi6_1.6.1-1+deb7u1_armhf.deb
+main/libx/libxi/libxi-dev_1.6.1-1+deb7u1_armhf.deb
+main/libx/libxinerama/libxinerama1_1.1.2-1+deb7u1_armhf.deb
+main/libx/libxinerama/libxinerama-dev_1.1.2-1+deb7u1_armhf.deb
+main/libx/libxrandr/libxrandr2_1.3.2-2+deb7u1_armhf.deb
+main/libx/libxrandr/libxrandr-dev_1.3.2-2+deb7u1_armhf.deb
+main/libx/libxrender/libxrender1_0.9.7-1+deb7u2_armhf.deb
+main/libx/libxrender/libxrender-dev_0.9.7-1+deb7u2_armhf.deb
+main/libx/libxss/libxss1_1.2.2-1_armhf.deb
+main/libx/libxss/libxss-dev_1.2.2-1_armhf.deb
+main/libx/libxt/libxt6_1.1.3-1+deb7u1_armhf.deb
+main/libx/libxt/libxt-dev_1.1.3-1+deb7u1_armhf.deb
+main/libx/libxtst/libxtst6_1.2.1-1+deb7u1_armhf.deb
+main/libx/libxtst/libxtst-dev_1.2.1-1+deb7u1_armhf.deb
+main/libx/libxxf86vm/libxxf86vm1_1.1.2-1+deb7u1_armhf.deb
+main/l/linux/linux-libc-dev_3.2.68-1+deb7u3_armhf.deb
+main/m/mesa/libgl1-mesa-dev_8.0.5-4+deb7u2_armhf.deb
+main/m/mesa/libgl1-mesa-glx_8.0.5-4+deb7u2_armhf.deb
+main/m/mesa/libglapi-mesa_8.0.5-4+deb7u2_armhf.deb
+main/m/mesa/mesa-common-dev_8.0.5-4+deb7u2_armhf.deb
+main/n/nspr/libnspr4_4.9.2-1+deb7u2_armhf.deb
+main/n/nspr/libnspr4-dev_4.9.2-1+deb7u2_armhf.deb
+main/n/nss/libnss3_3.14.5-1+deb7u5_armhf.deb
+main/n/nss/libnss3-dev_3.14.5-1+deb7u5_armhf.deb
+main/o/openssl/libssl1.0.0_1.0.1e-2+deb7u17_armhf.deb
+main/o/openssl/libssl-dev_1.0.1e-2+deb7u17_armhf.deb
+main/o/orbit2/liborbit2_2.14.19-0.1_armhf.deb
+main/p/p11-kit/libp11-kit0_0.12-3_armhf.deb
+main/p/pam/libpam0g_1.1.3-7.1_armhf.deb
+main/p/pam/libpam0g-dev_1.1.3-7.1_armhf.deb
+main/p/pango1.0/libpango1.0-0_1.30.0-1_armhf.deb
+main/p/pango1.0/libpango1.0-dev_1.30.0-1_armhf.deb
+main/p/pciutils/libpci3_3.1.9-6_armhf.deb
+main/p/pciutils/libpci-dev_3.1.9-6_armhf.deb
+main/p/pcre3/libpcre3_8.30-5_armhf.deb
+main/p/pcre3/libpcre3-dev_8.30-5_armhf.deb
+main/p/pcre3/libpcrecpp0_8.30-5_armhf.deb
+main/p/pixman/libpixman-1-0_0.26.0-4+deb7u1_armhf.deb
+main/p/pixman/libpixman-1-dev_0.26.0-4+deb7u1_armhf.deb
+main/p/pulseaudio/libpulse0_2.0-6.1_armhf.deb
+main/p/pulseaudio/libpulse-dev_2.0-6.1_armhf.deb
+main/p/pulseaudio/libpulse-mainloop-glib0_2.0-6.1_armhf.deb
+main/s/speech-dispatcher/libspeechd2_0.7.1-6.2_armhf.deb
+main/s/speech-dispatcher/libspeechd-dev_0.7.1-6.2_armhf.deb
+main/s/speech-dispatcher/speech-dispatcher_0.7.1-6.2_armhf.deb
+main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
+main/x/x11proto-core/x11proto-core-dev_7.0.23-1_all.deb
+main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
+main/x/x11proto-fixes/x11proto-fixes-dev_5.0-2_all.deb
+main/x/x11proto-input/x11proto-input-dev_2.2-1_all.deb
+main/x/x11proto-kb/x11proto-kb-dev_1.0.6-2_all.deb
+main/x/x11proto-randr/x11proto-randr-dev_1.3.2-2_all.deb
+main/x/x11proto-record/x11proto-record-dev_1.14.2-1_all.deb
+main/x/x11proto-render/x11proto-render-dev_0.11.1-2_all.deb
+main/x/x11proto-scrnsaver/x11proto-scrnsaver-dev_1.2.2-1_all.deb
+main/x/x11proto-xext/x11proto-xext-dev_7.2.1-1_all.deb
+main/z/zlib/zlib1g_1.2.7.dfsg-13_armhf.deb
+main/z/zlib/zlib1g-dev_1.2.7.dfsg-13_armhf.deb
diff --git a/build/linux/sysroot_scripts/packagelist.wheezy.i386 b/build/linux/sysroot_scripts/packagelist.wheezy.i386
new file mode 100644
index 0000000..8166600
--- /dev/null
+++ b/build/linux/sysroot_scripts/packagelist.wheezy.i386
@@ -0,0 +1,163 @@
+main/a/alsa-lib/libasound2_1.0.25-4_i386.deb
+main/a/alsa-lib/libasound2-dev_1.0.25-4_i386.deb
+main/a/atk1.0/libatk1.0-0_2.4.0-2_i386.deb
+main/a/atk1.0/libatk1.0-dev_2.4.0-2_i386.deb
+main/a/attr/libattr1_2.4.46-8_i386.deb
+main/a/avahi/libavahi-client3_0.6.31-2_i386.deb
+main/a/avahi/libavahi-common3_0.6.31-2_i386.deb
+main/c/cairo/libcairo2_1.12.2-3_i386.deb
+main/c/cairo/libcairo2-dev_1.12.2-3_i386.deb
+main/c/cairo/libcairo-gobject2_1.12.2-3_i386.deb
+main/c/cairo/libcairo-script-interpreter2_1.12.2-3_i386.deb
+main/c/cups/libcups2_1.5.3-5+deb7u6_i386.deb
+main/c/cups/libcups2-dev_1.5.3-5+deb7u6_i386.deb
+main/d/dbus-glib/libdbus-glib-1-2_0.100.2-1_i386.deb
+main/d/dbus/libdbus-1-3_1.6.8-1+deb7u6_i386.deb
+main/d/dbus/libdbus-1-dev_1.6.8-1+deb7u6_i386.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.5-1.1+deb7u1_i386.deb
+main/e/e2fsprogs/libcomerr2_1.42.5-1.1+deb7u1_i386.deb
+main/e/eglibc/libc6_2.13-38+deb7u8_i386.deb
+main/e/eglibc/libc6-dev_2.13-38+deb7u8_i386.deb
+main/e/elfutils/libelf1_0.152-1+wheezy1_i386.deb
+main/e/elfutils/libelf-dev_0.152-1+wheezy1_i386.deb
+main/e/expat/libexpat1_2.1.0-1+deb7u2_i386.deb
+main/e/expat/libexpat1-dev_2.1.0-1+deb7u2_i386.deb
+main/f/fontconfig/libfontconfig1_2.9.0-7.1_i386.deb
+main/f/fontconfig/libfontconfig1-dev_2.9.0-7.1_i386.deb
+main/f/freetype/libfreetype6_2.4.9-1.1+deb7u1_i386.deb
+main/f/freetype/libfreetype6-dev_2.4.9-1.1+deb7u1_i386.deb
+main/g/gcc-4.6/gcc-4.6_4.6.3-14_i386.deb
+main/g/gcc-4.6/libstdc++6-4.6-dev_4.6.3-14_i386.deb
+main/g/gcc-4.7/libgcc1_4.7.2-5_i386.deb
+main/g/gcc-4.7/libgomp1_4.7.2-5_i386.deb
+main/g/gcc-4.7/libquadmath0_4.7.2-5_i386.deb
+main/g/gcc-4.7/libstdc++6_4.7.2-5_i386.deb
+main/g/gconf/libgconf-2-4_3.2.5-1+build1_i386.deb
+main/g/gconf/libgconf2-4_3.2.5-1+build1_i386.deb
+main/g/gconf/libgconf2-dev_3.2.5-1+build1_i386.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.26.1-1+deb7u1_i386.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.26.1-1+deb7u1_i386.deb
+main/g/glib2.0/libglib2.0-0_2.33.12+really2.32.4-5_i386.deb
+main/g/glib2.0/libglib2.0-dev_2.33.12+really2.32.4-5_i386.deb
+main/g/gnutls26/libgnutls26_2.12.20-8+deb7u3_i386.deb
+main/g/gnutls26/libgnutls-dev_2.12.20-8+deb7u3_i386.deb
+main/g/gnutls26/libgnutls-openssl27_2.12.20-8+deb7u3_i386.deb
+main/g/gnutls26/libgnutlsxx27_2.12.20-8+deb7u3_i386.deb
+main/g/gtk+2.0/libgtk2.0-0_2.24.10-2_i386.deb
+main/g/gtk+2.0/libgtk2.0-dev_2.24.10-2_i386.deb
+main/k/keyutils/libkeyutils1_1.5.5-3+deb7u1_i386.deb
+main/k/krb5/krb5-multidev_1.10.1+dfsg-5+deb7u3_i386.deb
+main/k/krb5/libgssapi-krb5-2_1.10.1+dfsg-5+deb7u3_i386.deb
+main/k/krb5/libgssrpc4_1.10.1+dfsg-5+deb7u3_i386.deb
+main/k/krb5/libk5crypto3_1.10.1+dfsg-5+deb7u3_i386.deb
+main/k/krb5/libkadm5clnt-mit8_1.10.1+dfsg-5+deb7u3_i386.deb
+main/k/krb5/libkadm5srv-mit8_1.10.1+dfsg-5+deb7u3_i386.deb
+main/k/krb5/libkdb5-6_1.10.1+dfsg-5+deb7u3_i386.deb
+main/k/krb5/libkrb5-3_1.10.1+dfsg-5+deb7u3_i386.deb
+main/k/krb5/libkrb5-dev_1.10.1+dfsg-5+deb7u3_i386.deb
+main/k/krb5/libkrb5support0_1.10.1+dfsg-5+deb7u3_i386.deb
+main/libc/libcap2/libcap2_2.22-1.2_i386.deb
+main/libc/libcap2/libcap-dev_2.22-1.2_i386.deb
+main/libd/libdrm/libdrm2_2.4.40-1~deb7u2_i386.deb
+main/libd/libdrm/libdrm-dev_2.4.40-1~deb7u2_i386.deb
+main/libd/libdrm/libdrm-intel1_2.4.40-1~deb7u2_i386.deb
+main/libd/libdrm/libdrm-nouveau1a_2.4.40-1~deb7u2_i386.deb
+main/libd/libdrm/libdrm-radeon1_2.4.40-1~deb7u2_i386.deb
+main/libd/libdrm/libkms1_2.4.40-1~deb7u2_i386.deb
+main/libe/libexif/libexif12_0.6.20-3_i386.deb
+main/libe/libexif/libexif-dev_0.6.20-3_i386.deb
+main/libf/libffi/libffi5_3.0.10-3_i386.deb
+main/libf/libffi/libffi-dev_3.0.10-3_i386.deb
+main/libg/libgcrypt11/libgcrypt11_1.5.0-5+deb7u3_i386.deb
+main/libg/libgcrypt11/libgcrypt11-dev_1.5.0-5+deb7u3_i386.deb
+main/libg/libgnome-keyring/libgnome-keyring0_3.4.1-1_i386.deb
+main/libg/libgnome-keyring/libgnome-keyring-dev_3.4.1-1_i386.deb
+main/libg/libgpg-error/libgpg-error0_1.10-3.1_i386.deb
+main/libg/libgpg-error/libgpg-error-dev_1.10-3.1_i386.deb
+main/libn/libnss-db/libnss-db_2.2.3pre1-4_i386.deb
+main/libp/libp11/libp11-2_0.2.8-2_i386.deb
+main/libp/libpng/libpng12-0_1.2.49-1_i386.deb
+main/libp/libpng/libpng12-dev_1.2.49-1_i386.deb
+main/libs/libselinux/libselinux1_2.1.9-5_i386.deb
+main/libt/libtasn1-3/libtasn1-3_2.13-2+deb7u2_i386.deb
+main/libx/libx11/libx11-6_1.5.0-1+deb7u2_i386.deb
+main/libx/libx11/libx11-dev_1.5.0-1+deb7u2_i386.deb
+main/libx/libx11/libx11-xcb1_1.5.0-1+deb7u2_i386.deb
+main/libx/libxau/libxau6_1.0.7-1_i386.deb
+main/libx/libxau/libxau-dev_1.0.7-1_i386.deb
+main/libx/libxcb/libxcb1_1.8.1-2+deb7u1_i386.deb
+main/libx/libxcb/libxcb1-dev_1.8.1-2+deb7u1_i386.deb
+main/libx/libxcb/libxcb-glx0_1.8.1-2+deb7u1_i386.deb
+main/libx/libxcb/libxcb-render0_1.8.1-2+deb7u1_i386.deb
+main/libx/libxcb/libxcb-render0-dev_1.8.1-2+deb7u1_i386.deb
+main/libx/libxcb/libxcb-shm0_1.8.1-2+deb7u1_i386.deb
+main/libx/libxcb/libxcb-shm0-dev_1.8.1-2+deb7u1_i386.deb
+main/libx/libxcomposite/libxcomposite1_0.4.3-2_i386.deb
+main/libx/libxcomposite/libxcomposite-dev_0.4.3-2_i386.deb
+main/libx/libxcursor/libxcursor1_1.1.13-1+deb7u1_i386.deb
+main/libx/libxcursor/libxcursor-dev_1.1.13-1+deb7u1_i386.deb
+main/libx/libxdamage/libxdamage1_1.1.3-2_i386.deb
+main/libx/libxdamage/libxdamage-dev_1.1.3-2_i386.deb
+main/libx/libxdmcp/libxdmcp6_1.1.1-1_i386.deb
+main/libx/libxext/libxext6_1.3.1-2+deb7u1_i386.deb
+main/libx/libxext/libxext-dev_1.3.1-2+deb7u1_i386.deb
+main/libx/libxfixes/libxfixes3_5.0-4+deb7u1_i386.deb
+main/libx/libxfixes/libxfixes-dev_5.0-4+deb7u1_i386.deb
+main/libx/libxi/libxi6_1.6.1-1+deb7u1_i386.deb
+main/libx/libxi/libxi-dev_1.6.1-1+deb7u1_i386.deb
+main/libx/libxinerama/libxinerama1_1.1.2-1+deb7u1_i386.deb
+main/libx/libxinerama/libxinerama-dev_1.1.2-1+deb7u1_i386.deb
+main/libx/libxrandr/libxrandr2_1.3.2-2+deb7u1_i386.deb
+main/libx/libxrandr/libxrandr-dev_1.3.2-2+deb7u1_i386.deb
+main/libx/libxrender/libxrender1_0.9.7-1+deb7u2_i386.deb
+main/libx/libxrender/libxrender-dev_0.9.7-1+deb7u2_i386.deb
+main/libx/libxss/libxss1_1.2.2-1_i386.deb
+main/libx/libxss/libxss-dev_1.2.2-1_i386.deb
+main/libx/libxt/libxt6_1.1.3-1+deb7u1_i386.deb
+main/libx/libxt/libxt-dev_1.1.3-1+deb7u1_i386.deb
+main/libx/libxtst/libxtst6_1.2.1-1+deb7u1_i386.deb
+main/libx/libxtst/libxtst-dev_1.2.1-1+deb7u1_i386.deb
+main/libx/libxxf86vm/libxxf86vm1_1.1.2-1+deb7u1_i386.deb
+main/l/linux/linux-libc-dev_3.2.68-1+deb7u3_i386.deb
+main/m/mesa/libgl1-mesa-dev_8.0.5-4+deb7u2_i386.deb
+main/m/mesa/libgl1-mesa-glx_8.0.5-4+deb7u2_i386.deb
+main/m/mesa/libglapi-mesa_8.0.5-4+deb7u2_i386.deb
+main/m/mesa/mesa-common-dev_8.0.5-4+deb7u2_i386.deb
+main/n/nspr/libnspr4_4.9.2-1+deb7u2_i386.deb
+main/n/nspr/libnspr4-dev_4.9.2-1+deb7u2_i386.deb
+main/n/nss/libnss3_3.14.5-1+deb7u5_i386.deb
+main/n/nss/libnss3-dev_3.14.5-1+deb7u5_i386.deb
+main/o/openssl/libssl1.0.0_1.0.1e-2+deb7u17_i386.deb
+main/o/openssl/libssl-dev_1.0.1e-2+deb7u17_i386.deb
+main/o/orbit2/liborbit2_2.14.19-0.1_i386.deb
+main/p/p11-kit/libp11-kit0_0.12-3_i386.deb
+main/p/pam/libpam0g_1.1.3-7.1_i386.deb
+main/p/pam/libpam0g-dev_1.1.3-7.1_i386.deb
+main/p/pango1.0/libpango1.0-0_1.30.0-1_i386.deb
+main/p/pango1.0/libpango1.0-dev_1.30.0-1_i386.deb
+main/p/pciutils/libpci3_3.1.9-6_i386.deb
+main/p/pciutils/libpci-dev_3.1.9-6_i386.deb
+main/p/pcre3/libpcre3_8.30-5_i386.deb
+main/p/pcre3/libpcre3-dev_8.30-5_i386.deb
+main/p/pcre3/libpcrecpp0_8.30-5_i386.deb
+main/p/pixman/libpixman-1-0_0.26.0-4+deb7u1_i386.deb
+main/p/pixman/libpixman-1-dev_0.26.0-4+deb7u1_i386.deb
+main/p/pulseaudio/libpulse0_2.0-6.1_i386.deb
+main/p/pulseaudio/libpulse-dev_2.0-6.1_i386.deb
+main/p/pulseaudio/libpulse-mainloop-glib0_2.0-6.1_i386.deb
+main/s/speech-dispatcher/libspeechd2_0.7.1-6.2_i386.deb
+main/s/speech-dispatcher/libspeechd-dev_0.7.1-6.2_i386.deb
+main/s/speech-dispatcher/speech-dispatcher_0.7.1-6.2_i386.deb
+main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
+main/x/x11proto-core/x11proto-core-dev_7.0.23-1_all.deb
+main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
+main/x/x11proto-fixes/x11proto-fixes-dev_5.0-2_all.deb
+main/x/x11proto-input/x11proto-input-dev_2.2-1_all.deb
+main/x/x11proto-kb/x11proto-kb-dev_1.0.6-2_all.deb
+main/x/x11proto-randr/x11proto-randr-dev_1.3.2-2_all.deb
+main/x/x11proto-record/x11proto-record-dev_1.14.2-1_all.deb
+main/x/x11proto-render/x11proto-render-dev_0.11.1-2_all.deb
+main/x/x11proto-scrnsaver/x11proto-scrnsaver-dev_1.2.2-1_all.deb
+main/x/x11proto-xext/x11proto-xext-dev_7.2.1-1_all.deb
+main/z/zlib/zlib1g_1.2.7.dfsg-13_i386.deb
+main/z/zlib/zlib1g-dev_1.2.7.dfsg-13_i386.deb
diff --git a/build/linux/sysroot_scripts/packagelist.wheezy.mipsel b/build/linux/sysroot_scripts/packagelist.wheezy.mipsel
new file mode 100644
index 0000000..3398376
--- /dev/null
+++ b/build/linux/sysroot_scripts/packagelist.wheezy.mipsel
@@ -0,0 +1,161 @@
+main/a/alsa-lib/libasound2_1.0.25-4_mipsel.deb
+main/a/alsa-lib/libasound2-dev_1.0.25-4_mipsel.deb
+main/a/atk1.0/libatk1.0-0_2.4.0-2_mipsel.deb
+main/a/atk1.0/libatk1.0-dev_2.4.0-2_mipsel.deb
+main/a/attr/libattr1_2.4.46-8_mipsel.deb
+main/a/avahi/libavahi-client3_0.6.31-2_mipsel.deb
+main/a/avahi/libavahi-common3_0.6.31-2_mipsel.deb
+main/c/cairo/libcairo2_1.12.2-3_mipsel.deb
+main/c/cairo/libcairo2-dev_1.12.2-3_mipsel.deb
+main/c/cairo/libcairo-gobject2_1.12.2-3_mipsel.deb
+main/c/cairo/libcairo-script-interpreter2_1.12.2-3_mipsel.deb
+main/c/cups/libcups2_1.5.3-5+deb7u6_mipsel.deb
+main/c/cups/libcups2-dev_1.5.3-5+deb7u6_mipsel.deb
+main/d/dbus-glib/libdbus-glib-1-2_0.100.2-1_mipsel.deb
+main/d/dbus/libdbus-1-3_1.6.8-1+deb7u6_mipsel.deb
+main/d/dbus/libdbus-1-dev_1.6.8-1+deb7u6_mipsel.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.5-1.1+deb7u1_mipsel.deb
+main/e/e2fsprogs/libcomerr2_1.42.5-1.1+deb7u1_mipsel.deb
+main/e/eglibc/libc6_2.13-38+deb7u8_mipsel.deb
+main/e/eglibc/libc6-dev_2.13-38+deb7u8_mipsel.deb
+main/e/elfutils/libelf1_0.152-1+wheezy1_mipsel.deb
+main/e/elfutils/libelf-dev_0.152-1+wheezy1_mipsel.deb
+main/e/expat/libexpat1_2.1.0-1+deb7u2_mipsel.deb
+main/e/expat/libexpat1-dev_2.1.0-1+deb7u2_mipsel.deb
+main/f/fontconfig/libfontconfig1_2.9.0-7.1_mipsel.deb
+main/f/fontconfig/libfontconfig1-dev_2.9.0-7.1_mipsel.deb
+main/f/freetype/libfreetype6_2.4.9-1.1+deb7u1_mipsel.deb
+main/f/freetype/libfreetype6-dev_2.4.9-1.1+deb7u1_mipsel.deb
+main/g/gcc-4.6/gcc-4.6_4.6.3-14_mipsel.deb
+main/g/gcc-4.6/libstdc++6-4.6-dev_4.6.3-14_mipsel.deb
+main/g/gcc-4.7/libgcc1_4.7.2-5_mipsel.deb
+main/g/gcc-4.7/libgomp1_4.7.2-5_mipsel.deb
+main/g/gcc-4.7/libstdc++6_4.7.2-5_mipsel.deb
+main/g/gconf/libgconf2-4_3.2.5-1+build1_mipsel.deb
+main/g/gconf/libgconf-2-4_3.2.5-1+build1_mipsel.deb
+main/g/gconf/libgconf2-dev_3.2.5-1+build1_mipsel.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.26.1-1+deb7u1_mipsel.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.26.1-1+deb7u1_mipsel.deb
+main/g/glib2.0/libglib2.0-0_2.33.12+really2.32.4-5_mipsel.deb
+main/g/glib2.0/libglib2.0-dev_2.33.12+really2.32.4-5_mipsel.deb
+main/g/gnutls26/libgnutls26_2.12.20-8+deb7u3_mipsel.deb
+main/g/gnutls26/libgnutls-dev_2.12.20-8+deb7u3_mipsel.deb
+main/g/gnutls26/libgnutls-openssl27_2.12.20-8+deb7u3_mipsel.deb
+main/g/gnutls26/libgnutlsxx27_2.12.20-8+deb7u3_mipsel.deb
+main/g/gtk+2.0/libgtk2.0-0_2.24.10-2_mipsel.deb
+main/g/gtk+2.0/libgtk2.0-dev_2.24.10-2_mipsel.deb
+main/k/keyutils/libkeyutils1_1.5.5-3+deb7u1_mipsel.deb
+main/k/krb5/krb5-multidev_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/k/krb5/libgssapi-krb5-2_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/k/krb5/libgssrpc4_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/k/krb5/libk5crypto3_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/k/krb5/libkadm5clnt-mit8_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/k/krb5/libkadm5srv-mit8_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/k/krb5/libkdb5-6_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/k/krb5/libkrb5-3_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/k/krb5/libkrb5-dev_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/k/krb5/libkrb5support0_1.10.1+dfsg-5+deb7u3_mipsel.deb
+main/libc/libcap2/libcap2_2.22-1.2_mipsel.deb
+main/libc/libcap2/libcap-dev_2.22-1.2_mipsel.deb
+main/libd/libdrm/libdrm2_2.4.40-1~deb7u2_mipsel.deb
+main/libd/libdrm/libdrm-dev_2.4.40-1~deb7u2_mipsel.deb
+main/libd/libdrm/libdrm-nouveau1a_2.4.40-1~deb7u2_mipsel.deb
+main/libd/libdrm/libdrm-radeon1_2.4.40-1~deb7u2_mipsel.deb
+main/libd/libdrm/libkms1_2.4.40-1~deb7u2_mipsel.deb
+main/libe/libexif/libexif12_0.6.20-3_mipsel.deb
+main/libe/libexif/libexif-dev_0.6.20-3_mipsel.deb
+main/libf/libffi/libffi5_3.0.10-3_mipsel.deb
+main/libf/libffi/libffi-dev_3.0.10-3_mipsel.deb
+main/libg/libgcrypt11/libgcrypt11_1.5.0-5+deb7u3_mipsel.deb
+main/libg/libgcrypt11/libgcrypt11-dev_1.5.0-5+deb7u3_mipsel.deb
+main/libg/libgnome-keyring/libgnome-keyring0_3.4.1-1_mipsel.deb
+main/libg/libgnome-keyring/libgnome-keyring-dev_3.4.1-1_mipsel.deb
+main/libg/libgpg-error/libgpg-error0_1.10-3.1_mipsel.deb
+main/libg/libgpg-error/libgpg-error-dev_1.10-3.1_mipsel.deb
+main/libn/libnss-db/libnss-db_2.2.3pre1-4_mipsel.deb
+main/libp/libp11/libp11-2_0.2.8-2_mipsel.deb
+main/libp/libpng/libpng12-0_1.2.49-1_mipsel.deb
+main/libp/libpng/libpng12-dev_1.2.49-1_mipsel.deb
+main/libs/libselinux/libselinux1_2.1.9-5_mipsel.deb
+main/libt/libtasn1-3/libtasn1-3_2.13-2+deb7u2_mipsel.deb
+main/libx/libx11/libx11-6_1.5.0-1+deb7u2_mipsel.deb
+main/libx/libx11/libx11-dev_1.5.0-1+deb7u2_mipsel.deb
+main/libx/libx11/libx11-xcb1_1.5.0-1+deb7u2_mipsel.deb
+main/libx/libxau/libxau6_1.0.7-1_mipsel.deb
+main/libx/libxau/libxau-dev_1.0.7-1_mipsel.deb
+main/libx/libxcb/libxcb1_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb1-dev_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-glx0_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-render0_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-render0-dev_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-shm0_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-shm0-dev_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcomposite/libxcomposite1_0.4.3-2_mipsel.deb
+main/libx/libxcomposite/libxcomposite-dev_0.4.3-2_mipsel.deb
+main/libx/libxcursor/libxcursor1_1.1.13-1+deb7u1_mipsel.deb
+main/libx/libxcursor/libxcursor-dev_1.1.13-1+deb7u1_mipsel.deb
+main/libx/libxdamage/libxdamage1_1.1.3-2_mipsel.deb
+main/libx/libxdamage/libxdamage-dev_1.1.3-2_mipsel.deb
+main/libx/libxdmcp/libxdmcp6_1.1.1-1_mipsel.deb
+main/libx/libxext/libxext6_1.3.1-2+deb7u1_mipsel.deb
+main/libx/libxext/libxext-dev_1.3.1-2+deb7u1_mipsel.deb
+main/libx/libxfixes/libxfixes3_5.0-4+deb7u1_mipsel.deb
+main/libx/libxfixes/libxfixes-dev_5.0-4+deb7u1_mipsel.deb
+main/libx/libxi/libxi6_1.6.1-1+deb7u1_mipsel.deb
+main/libx/libxi/libxi-dev_1.6.1-1+deb7u1_mipsel.deb
+main/libx/libxinerama/libxinerama1_1.1.2-1+deb7u1_mipsel.deb
+main/libx/libxinerama/libxinerama-dev_1.1.2-1+deb7u1_mipsel.deb
+main/libx/libxrandr/libxrandr2_1.3.2-2+deb7u1_mipsel.deb
+main/libx/libxrandr/libxrandr-dev_1.3.2-2+deb7u1_mipsel.deb
+main/libx/libxrender/libxrender1_0.9.7-1+deb7u2_mipsel.deb
+main/libx/libxrender/libxrender-dev_0.9.7-1+deb7u2_mipsel.deb
+main/libx/libxss/libxss1_1.2.2-1_mipsel.deb
+main/libx/libxss/libxss-dev_1.2.2-1_mipsel.deb
+main/libx/libxt/libxt6_1.1.3-1+deb7u1_mipsel.deb
+main/libx/libxt/libxt-dev_1.1.3-1+deb7u1_mipsel.deb
+main/libx/libxtst/libxtst6_1.2.1-1+deb7u1_mipsel.deb
+main/libx/libxtst/libxtst-dev_1.2.1-1+deb7u1_mipsel.deb
+main/libx/libxxf86vm/libxxf86vm1_1.1.2-1+deb7u1_mipsel.deb
+main/l/linux/linux-libc-dev_3.2.68-1+deb7u3_mipsel.deb
+main/m/mesa/libgl1-mesa-dev_8.0.5-4+deb7u2_mipsel.deb
+main/m/mesa/libgl1-mesa-glx_8.0.5-4+deb7u2_mipsel.deb
+main/m/mesa/libglapi-mesa_8.0.5-4+deb7u2_mipsel.deb
+main/m/mesa/mesa-common-dev_8.0.5-4+deb7u2_mipsel.deb
+main/n/nspr/libnspr4_4.9.2-1+deb7u2_mipsel.deb
+main/n/nspr/libnspr4-dev_4.9.2-1+deb7u2_mipsel.deb
+main/n/nss/libnss3_3.14.5-1+deb7u5_mipsel.deb
+main/n/nss/libnss3-dev_3.14.5-1+deb7u5_mipsel.deb
+main/o/openssl/libssl1.0.0_1.0.1e-2+deb7u17_mipsel.deb
+main/o/openssl/libssl-dev_1.0.1e-2+deb7u17_mipsel.deb
+main/o/orbit2/liborbit2_2.14.19-0.1_mipsel.deb
+main/p/p11-kit/libp11-kit0_0.12-3_mipsel.deb
+main/p/pam/libpam0g_1.1.3-7.1_mipsel.deb
+main/p/pam/libpam0g-dev_1.1.3-7.1_mipsel.deb
+main/p/pango1.0/libpango1.0-0_1.30.0-1_mipsel.deb
+main/p/pango1.0/libpango1.0-dev_1.30.0-1_mipsel.deb
+main/p/pciutils/libpci3_3.1.9-6_mipsel.deb
+main/p/pciutils/libpci-dev_3.1.9-6_mipsel.deb
+main/p/pcre3/libpcre3_8.30-5_mipsel.deb
+main/p/pcre3/libpcre3-dev_8.30-5_mipsel.deb
+main/p/pcre3/libpcrecpp0_8.30-5_mipsel.deb
+main/p/pixman/libpixman-1-0_0.26.0-4+deb7u1_mipsel.deb
+main/p/pixman/libpixman-1-dev_0.26.0-4+deb7u1_mipsel.deb
+main/p/pulseaudio/libpulse0_2.0-6.1_mipsel.deb
+main/p/pulseaudio/libpulse-dev_2.0-6.1_mipsel.deb
+main/p/pulseaudio/libpulse-mainloop-glib0_2.0-6.1_mipsel.deb
+main/s/speech-dispatcher/libspeechd2_0.7.1-6.2_mipsel.deb
+main/s/speech-dispatcher/libspeechd-dev_0.7.1-6.2_mipsel.deb
+main/s/speech-dispatcher/speech-dispatcher_0.7.1-6.2_mipsel.deb
+main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
+main/x/x11proto-core/x11proto-core-dev_7.0.23-1_all.deb
+main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
+main/x/x11proto-fixes/x11proto-fixes-dev_5.0-2_all.deb
+main/x/x11proto-input/x11proto-input-dev_2.2-1_all.deb
+main/x/x11proto-kb/x11proto-kb-dev_1.0.6-2_all.deb
+main/x/x11proto-randr/x11proto-randr-dev_1.3.2-2_all.deb
+main/x/x11proto-record/x11proto-record-dev_1.14.2-1_all.deb
+main/x/x11proto-render/x11proto-render-dev_0.11.1-2_all.deb
+main/x/x11proto-scrnsaver/x11proto-scrnsaver-dev_1.2.2-1_all.deb
+main/x/x11proto-xext/x11proto-xext-dev_7.2.1-1_all.deb
+main/z/zlib/zlib1g_1.2.7.dfsg-13_mipsel.deb
+main/z/zlib/zlib1g-dev_1.2.7.dfsg-13_mipsel.deb
diff --git a/build/linux/sysroot_scripts/sysroot-creator-test.sh b/build/linux/sysroot_scripts/sysroot-creator-test.sh
new file mode 100755
index 0000000..b346bb7
--- /dev/null
+++ b/build/linux/sysroot_scripts/sysroot-creator-test.sh
@@ -0,0 +1,23 @@
+#!/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.
+#
+# Rudimentry test suite for sysroot-creator.
+
+SCRIPT_DIR=$(dirname $0)
+
+set -o errexit
+
+TestUpdateAllLists() {
+  echo "[ RUN      ] TestUpdateAllLists"
+  "$SCRIPT_DIR/sysroot-creator-trusty.sh" UpdatePackageListsAmd64
+  "$SCRIPT_DIR/sysroot-creator-trusty.sh" UpdatePackageListsI386
+  "$SCRIPT_DIR/sysroot-creator-trusty.sh" UpdatePackageListsARM
+  "$SCRIPT_DIR/sysroot-creator-wheezy.sh" UpdatePackageListsAmd64
+  "$SCRIPT_DIR/sysroot-creator-wheezy.sh" UpdatePackageListsI386
+  "$SCRIPT_DIR/sysroot-creator-wheezy.sh" UpdatePackageListsARM
+  echo "[      OK  ]"
+}
+
+TestUpdateAllLists
diff --git a/build/linux/sysroot_scripts/sysroot-creator-trusty.sh b/build/linux/sysroot_scripts/sysroot-creator-trusty.sh
new file mode 100755
index 0000000..7c5e346
--- /dev/null
+++ b/build/linux/sysroot_scripts/sysroot-creator-trusty.sh
@@ -0,0 +1,183 @@
+#!/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.
+
+SCRIPT_DIR=$(dirname $0)
+
+DISTRO=ubuntu
+DIST=trusty
+
+# This is where we get all the debian packages from.
+APT_REPO=http://archive.ubuntu.com/ubuntu
+APT_REPO_ARM=http://ports.ubuntu.com
+REPO_BASEDIR="${APT_REPO}/dists/${DIST}"
+KEYRING_FILE=/usr/share/keyrings/ubuntu-archive-keyring.gpg
+
+# Sysroot packages: these are the packages needed to build chrome.
+# NOTE: When DEBIAN_PACKAGES is modified, the packagelist files must be updated
+# by running this script in GeneratePackageList mode.
+DEBIAN_PACKAGES="\
+  comerr-dev
+  gcc-4.8
+  krb5-multidev
+  libasound2
+  libasound2-dev
+  libatk1.0-0
+  libatk1.0-dev
+  libavahi-client3
+  libavahi-common3
+  libc6
+  libc6-dev
+  libcairo2
+  libcairo2-dev
+  libcairo-gobject2
+  libcairo-script-interpreter2
+  libcap-dev
+  libcap2
+  libcomerr2
+  libcups2
+  libcups2-dev
+  libdbus-1-3
+  libdbus-1-dev
+  libdbus-glib-1-2
+  libdrm2
+  libelf1
+  libelf-dev
+  libexif12
+  libexif-dev
+  libexpat1
+  libexpat1-dev
+  libffi6
+  libfontconfig1
+  libfontconfig1-dev
+  libfreetype6
+  libfreetype6-dev
+  libgcc1
+  libgconf-2-4
+  libgconf2-4
+  libgconf2-dev
+  libgcrypt11
+  libgcrypt11-dev
+  libgdk-pixbuf2.0-0
+  libgdk-pixbuf2.0-dev
+  libgl1-mesa-dev
+  libgl1-mesa-glx
+  libglapi-mesa
+  libglib2.0-0
+  libglib2.0-dev
+  libgnome-keyring0
+  libgnome-keyring-dev
+  libgnutls26
+  libgnutls-dev
+  libgnutls-openssl27
+  libgnutlsxx27
+  libgomp1
+  libgpg-error0
+  libgpg-error-dev
+  libgssapi-krb5-2
+  libgssrpc4
+  libgtk2.0-0
+  libgtk2.0-dev
+  libk5crypto3
+  libkadm5clnt-mit9
+  libkadm5srv-mit9
+  libkdb5-7
+  libkeyutils1
+  libkrb5-3
+  libkrb5-dev
+  libkrb5support0
+  libnspr4
+  libnspr4-dev
+  libnss3
+  libnss3-dev
+  libnss-db
+  liborbit2
+  libp11-2
+  libp11-kit0
+  libpam0g
+  libpam0g-dev
+  libpango-1.0-0
+  libpango1.0-dev
+  libpangocairo-1.0-0
+  libpangoft2-1.0-0
+  libpangoxft-1.0-0
+  libpci3
+  libpci-dev
+  libpcre3
+  libpcre3-dev
+  libpcrecpp0
+  libpixman-1-0
+  libpixman-1-dev
+  libpng12-0
+  libpng12-dev
+  libpulse0
+  libpulse-dev
+  libpulse-mainloop-glib0
+  libselinux1
+  libspeechd2
+  libspeechd-dev
+  libssl1.0.0
+  libssl-dev
+  libstdc++6
+  libstdc++-4.8-dev
+  libtasn1-6
+  libx11-6
+  libx11-dev
+  libx11-xcb1
+  libxau6
+  libxau-dev
+  libxcb1
+  libxcb1-dev
+  libxcb-glx0
+  libxcb-render0
+  libxcb-render0-dev
+  libxcb-shm0
+  libxcb-shm0-dev
+  libxcomposite1
+  libxcomposite-dev
+  libxcursor1
+  libxcursor-dev
+  libxdamage1
+  libxdamage-dev
+  libxdmcp6
+  libxext6
+  libxext-dev
+  libxfixes3
+  libxfixes-dev
+  libxi6
+  libxi-dev
+  libxinerama1
+  libxinerama-dev
+  libxrandr2
+  libxrandr-dev
+  libxrender1
+  libxrender-dev
+  libxss1
+  libxss-dev
+  libxt6
+  libxt-dev
+  libxtst6
+  libxtst-dev
+  libxxf86vm1
+  linux-libc-dev
+  mesa-common-dev
+  speech-dispatcher
+  x11proto-composite-dev
+  x11proto-core-dev
+  x11proto-damage-dev
+  x11proto-fixes-dev
+  x11proto-input-dev
+  x11proto-kb-dev
+  x11proto-randr-dev
+  x11proto-record-dev
+  x11proto-render-dev
+  x11proto-scrnsaver-dev
+  x11proto-xext-dev
+  zlib1g
+  zlib1g-dev
+"
+
+DEBIAN_PACKAGES_X86="libquadmath0"
+
+. ${SCRIPT_DIR}/sysroot-creator.sh
diff --git a/build/linux/sysroot_scripts/sysroot-creator-wheezy.sh b/build/linux/sysroot_scripts/sysroot-creator-wheezy.sh
new file mode 100755
index 0000000..63230e1
--- /dev/null
+++ b/build/linux/sysroot_scripts/sysroot-creator-wheezy.sh
@@ -0,0 +1,184 @@
+#!/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.
+
+SCRIPT_DIR=$(dirname $0)
+
+DISTRO=debian
+DIST=wheezy
+APT_REPO=http://http.us.debian.org/debian
+REPO_BASEDIR="${APT_REPO}/dists/${DIST}"
+KEYRING_FILE=/usr/share/keyrings/debian-archive-keyring.gpg
+
+# Sysroot packages: these are the packages needed to build chrome.
+# NOTE: When DEBIAN_PACKAGES is modified, the packagelist files must be updated
+# by running this script in GeneratePackageList mode.
+DEBIAN_PACKAGES="\
+  comerr-dev
+  gcc-4.6
+  krb5-multidev
+  libasound2
+  libasound2-dev
+  libatk1.0-0
+  libatk1.0-dev
+  libattr1
+  libavahi-client3
+  libavahi-common3
+  libc6
+  libc6-dev
+  libcairo2
+  libcairo2-dev
+  libcairo-gobject2
+  libcairo-script-interpreter2
+  libcap-dev
+  libcap2
+  libcomerr2
+  libcups2
+  libcups2-dev
+  libdbus-1-3
+  libdbus-1-dev
+  libdbus-glib-1-2
+  libdrm2
+  libdrm-dev
+  libdrm-nouveau1a
+  libdrm-radeon1
+  libelf1
+  libelf-dev
+  libexif12
+  libexif-dev
+  libexpat1
+  libexpat1-dev
+  libffi5
+  libffi-dev
+  libfontconfig1
+  libfontconfig1-dev
+  libfreetype6
+  libfreetype6-dev
+  libgcc1
+  libgconf-2-4
+  libgconf2-4
+  libgconf2-dev
+  libgcrypt11
+  libgcrypt11-dev
+  libgdk-pixbuf2.0-0
+  libgdk-pixbuf2.0-dev
+  libgl1-mesa-dev
+  libgl1-mesa-glx
+  libglapi-mesa
+  libglib2.0-0
+  libglib2.0-dev
+  libgnome-keyring0
+  libgnome-keyring-dev
+  libgnutls26
+  libgnutls-dev
+  libgnutls-openssl27
+  libgnutlsxx27
+  libgomp1
+  libgpg-error0
+  libgpg-error-dev
+  libgssapi-krb5-2
+  libgssrpc4
+  libgtk2.0-0
+  libgtk2.0-dev
+  libk5crypto3
+  libkadm5clnt-mit8
+  libkadm5srv-mit8
+  libkdb5-6
+  libkeyutils1
+  libkms1
+  libkrb5-3
+  libkrb5-dev
+  libkrb5support0
+  libnspr4
+  libnspr4-dev
+  libnss3
+  libnss3-dev
+  libnss-db
+  liborbit2
+  libp11-2
+  libp11-kit0
+  libpam0g
+  libpam0g-dev
+  libpango1.0-0
+  libpango1.0-dev
+  libpci3
+  libpci-dev
+  libpcre3
+  libpcre3-dev
+  libpcrecpp0
+  libpixman-1-0
+  libpixman-1-dev
+  libpng12-0
+  libpng12-dev
+  libpulse0
+  libpulse-dev
+  libpulse-mainloop-glib0
+  libselinux1
+  libspeechd2
+  libspeechd-dev
+  libssl1.0.0
+  libssl-dev
+  libstdc++6
+  libstdc++6-4.6-dev
+  libtasn1-3
+  libx11-6
+  libx11-dev
+  libx11-xcb1
+  libxau6
+  libxau-dev
+  libxcb1
+  libxcb1-dev
+  libxcb-glx0
+  libxcb-render0
+  libxcb-render0-dev
+  libxcb-shm0
+  libxcb-shm0-dev
+  libxcomposite1
+  libxcomposite-dev
+  libxcursor1
+  libxcursor-dev
+  libxdamage1
+  libxdamage-dev
+  libxdmcp6
+  libxext6
+  libxext-dev
+  libxfixes3
+  libxfixes-dev
+  libxi6
+  libxi-dev
+  libxinerama1
+  libxinerama-dev
+  libxrandr2
+  libxrandr-dev
+  libxrender1
+  libxrender-dev
+  libxss1
+  libxss-dev
+  libxt6
+  libxt-dev
+  libxtst6
+  libxtst-dev
+  libxxf86vm1
+  linux-libc-dev
+  mesa-common-dev
+  speech-dispatcher
+  x11proto-composite-dev
+  x11proto-core-dev
+  x11proto-damage-dev
+  x11proto-fixes-dev
+  x11proto-input-dev
+  x11proto-kb-dev
+  x11proto-randr-dev
+  x11proto-record-dev
+  x11proto-render-dev
+  x11proto-scrnsaver-dev
+  x11proto-xext-dev
+  zlib1g
+  zlib1g-dev
+"
+
+DEBIAN_PACKAGES_X86="libquadmath0 libdrm-intel1"
+DEBIAN_PACKAGES_ARM="libdrm-omap1"
+
+. ${SCRIPT_DIR}/sysroot-creator.sh
diff --git a/build/linux/sysroot_scripts/sysroot-creator.sh b/build/linux/sysroot_scripts/sysroot-creator.sh
new file mode 100644
index 0000000..cdbb036
--- /dev/null
+++ b/build/linux/sysroot_scripts/sysroot-creator.sh
@@ -0,0 +1,706 @@
+# Copyright 2014 The Chromium Authors. 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 should not be run directly but sourced by the other
+# scripts (e.g. sysroot-creator-trusty.sh).  Its up to the parent scripts
+# to define certain environment variables: e.g.
+#  DISTRO=ubuntu
+#  DIST=trusty
+#  APT_REPO=http://archive.ubuntu.com/ubuntu
+#  KEYRING_FILE=/usr/share/keyrings/ubuntu-archive-keyring.gpg
+#  DEBIAN_PACKAGES="gcc libz libssl"
+
+#@ This script builds a Debian sysroot images for building Google Chrome.
+#@
+#@  Generally this script is invoked as:
+#@  sysroot-creator-<flavour>.sh <mode> <args>*
+#@  Available modes are shown below.
+#@
+#@ List of modes:
+
+######################################################################
+# Config
+######################################################################
+
+set -o nounset
+set -o errexit
+
+SCRIPT_DIR=$(cd $(dirname $0) && pwd)
+
+if [ -z "${DIST:-}" ]; then
+  echo "error: DIST not defined"
+  exit 1
+fi
+
+if [ -z "${APT_REPO:-}" ]; then
+  echo "error: APT_REPO not defined"
+  exit 1
+fi
+
+if [ -z "${KEYRING_FILE:-}" ]; then
+  echo "error: KEYRING_FILE not defined"
+  exit 1
+fi
+
+if [ -z "${DEBIAN_PACKAGES:-}" ]; then
+  echo "error: DEBIAN_PACKAGES not defined"
+  exit 1
+fi
+
+readonly REPO_BASEDIR="${APT_REPO}/dists/${DIST}"
+
+readonly REQUIRED_TOOLS="wget"
+
+######################################################################
+# Package Config
+######################################################################
+
+readonly RELEASE_FILE="Release"
+readonly RELEASE_FILE_GPG="Release.gpg"
+readonly RELEASE_LIST="${REPO_BASEDIR}/${RELEASE_FILE}"
+readonly RELEASE_LIST_GPG="${REPO_BASEDIR}/${RELEASE_FILE_GPG}"
+readonly PACKAGE_FILE_AMD64="main/binary-amd64/Packages.bz2"
+readonly PACKAGE_FILE_I386="main/binary-i386/Packages.bz2"
+readonly PACKAGE_FILE_ARM="main/binary-armhf/Packages.bz2"
+readonly PACKAGE_FILE_MIPS="main/binary-mipsel/Packages.bz2"
+readonly PACKAGE_LIST_AMD64="${REPO_BASEDIR}/${PACKAGE_FILE_AMD64}"
+readonly PACKAGE_LIST_I386="${REPO_BASEDIR}/${PACKAGE_FILE_I386}"
+readonly PACKAGE_LIST_ARM="${REPO_BASEDIR}/${PACKAGE_FILE_ARM}"
+readonly PACKAGE_LIST_MIPS="${REPO_BASEDIR}/${PACKAGE_FILE_MIPS}"
+
+readonly DEBIAN_DEP_LIST_AMD64="packagelist.${DIST}.amd64"
+readonly DEBIAN_DEP_LIST_I386="packagelist.${DIST}.i386"
+readonly DEBIAN_DEP_LIST_ARM="packagelist.${DIST}.arm"
+readonly DEBIAN_DEP_LIST_MIPS="packagelist.${DIST}.mipsel"
+
+######################################################################
+# Helper
+######################################################################
+
+Banner() {
+  echo "######################################################################"
+  echo $*
+  echo "######################################################################"
+}
+
+
+SubBanner() {
+  echo "----------------------------------------------------------------------"
+  echo $*
+  echo "----------------------------------------------------------------------"
+}
+
+
+Usage() {
+  egrep "^#@" "${BASH_SOURCE[0]}" | cut --bytes=3-
+}
+
+
+DownloadOrCopy() {
+  if [ -f "$2" ] ; then
+    echo "$2 already in place"
+    return
+  fi
+
+  HTTP=0
+  echo "$1" | grep -qs ^http:// && HTTP=1
+  if [ "$HTTP" = "1" ]; then
+    SubBanner "downloading from $1 -> $2"
+    wget "$1" -O "${2}.partial"
+    mv "${2}.partial" $2
+  else
+    SubBanner "copying from $1"
+    cp "$1" "$2"
+  fi
+}
+
+
+SetEnvironmentVariables() {
+  ARCH=""
+  echo $1 | grep -qs Amd64$ && ARCH=AMD64
+  if [ -z "$ARCH" ]; then
+    echo $1 | grep -qs I386$ && ARCH=I386
+  fi
+  if [ -z "$ARCH" ]; then
+    echo $1 | grep -qs Mips$ && ARCH=MIPS
+  fi
+  if [ -z "$ARCH" ]; then
+    echo $1 | grep -qs ARM$ && ARCH=ARM
+  fi
+  if [ -z "${ARCH}" ]; then
+    echo "ERROR: Unable to determine architecture based on: $1"
+    exit 1
+  fi
+  ARCH_LOWER=$(echo $ARCH | tr '[:upper:]' '[:lower:]')
+}
+
+
+# some sanity checks to make sure this script is run from the right place
+# with the right tools
+SanityCheck() {
+  Banner "Sanity Checks"
+
+  local chrome_dir=$(cd "${SCRIPT_DIR}/../../.." && pwd)
+  BUILD_DIR="${chrome_dir}/out/sysroot-build/${DIST}"
+  mkdir -p ${BUILD_DIR}
+  echo "Using build directory: ${BUILD_DIR}"
+
+  for tool in ${REQUIRED_TOOLS} ; do
+    if ! which ${tool} > /dev/null ; then
+      echo "Required binary $tool not found."
+      echo "Exiting."
+      exit 1
+    fi
+  done
+
+  # This is where the staging sysroot is.
+  INSTALL_ROOT="${BUILD_DIR}/${DIST}_${ARCH_LOWER}_staging"
+  TARBALL="${BUILD_DIR}/${DISTRO}_${DIST}_${ARCH_LOWER}_sysroot.tgz"
+
+  if ! mkdir -p "${INSTALL_ROOT}" ; then
+    echo "ERROR: ${INSTALL_ROOT} can't be created."
+    exit 1
+  fi
+}
+
+
+ChangeDirectory() {
+  # Change directory to where this script is.
+  cd ${SCRIPT_DIR}
+}
+
+
+ClearInstallDir() {
+  Banner "Clearing dirs in ${INSTALL_ROOT}"
+  rm -rf ${INSTALL_ROOT}/*
+}
+
+
+CreateTarBall() {
+  Banner "Creating tarball ${TARBALL}"
+  tar zcf ${TARBALL} -C ${INSTALL_ROOT} .
+}
+
+ExtractPackageBz2() {
+  bzcat "$1" | egrep '^(Package:|Filename:|SHA256:) ' > "$2"
+}
+
+GeneratePackageListAmd64() {
+  local output_file="$1"
+  local package_list="${BUILD_DIR}/Packages.${DIST}_amd64.bz2"
+  local tmp_package_list="${BUILD_DIR}/Packages.${DIST}_amd64"
+  DownloadOrCopy "${PACKAGE_LIST_AMD64}" "${package_list}"
+  VerifyPackageListing "${PACKAGE_FILE_AMD64}" "${package_list}"
+  ExtractPackageBz2 "$package_list" "$tmp_package_list"
+  GeneratePackageList "$tmp_package_list" "$output_file" "${DEBIAN_PACKAGES}
+    ${DEBIAN_PACKAGES_X86}"
+}
+
+GeneratePackageListI386() {
+  local output_file="$1"
+  local package_list="${BUILD_DIR}/Packages.${DIST}_i386.bz2"
+  local tmp_package_list="${BUILD_DIR}/Packages.${DIST}_amd64"
+  DownloadOrCopy "${PACKAGE_LIST_I386}" "${package_list}"
+  VerifyPackageListing "${PACKAGE_FILE_I386}" "${package_list}"
+  ExtractPackageBz2 "$package_list" "$tmp_package_list"
+  GeneratePackageList "$tmp_package_list" "$output_file" "${DEBIAN_PACKAGES}
+    ${DEBIAN_PACKAGES_X86}"
+}
+
+GeneratePackageListARM() {
+  local output_file="$1"
+  local package_list="${BUILD_DIR}/Packages.${DIST}_arm.bz2"
+  local tmp_package_list="${BUILD_DIR}/Packages.${DIST}_arm"
+  DownloadOrCopy "${PACKAGE_LIST_ARM}" "${package_list}"
+  VerifyPackageListing "${PACKAGE_FILE_ARM}" "${package_list}"
+  ExtractPackageBz2 "$package_list" "$tmp_package_list"
+  GeneratePackageList "$tmp_package_list" "$output_file" "${DEBIAN_PACKAGES}
+    ${DEBIAN_PACKAGES_ARM}"
+}
+
+GeneratePackageListMips() {
+  local output_file="$1"
+  local package_list="${BUILD_DIR}/Packages.${DIST}_mips.bz2"
+  local tmp_package_list="${BUILD_DIR}/Packages.${DIST}_mips"
+  DownloadOrCopy "${PACKAGE_LIST_MIPS}" "${package_list}"
+  VerifyPackageListing "${PACKAGE_FILE_MIPS}" "${package_list}"
+  ExtractPackageBz2 "$package_list" "$tmp_package_list"
+  GeneratePackageList "$tmp_package_list" "$output_file" "${DEBIAN_PACKAGES}"
+}
+
+StripChecksumsFromPackageList() {
+  local package_file="$1"
+  sed -i 's/ [a-f0-9]\{64\}$//' "$package_file"
+}
+
+VerifyPackageFilesMatch() {
+  local downloaded_package_file="$1"
+  local stored_package_file="$2"
+  diff -u "$downloaded_package_file" "$stored_package_file"
+  if [ "$?" -ne "0" ]; then
+    echo "ERROR: downloaded package files does not match $2."
+    echo "You may need to run UpdatePackageLists."
+    exit 1
+  fi
+}
+
+######################################################################
+#
+######################################################################
+
+HacksAndPatchesAmd64() {
+  Banner "Misc Hacks & Patches"
+  # these are linker scripts with absolute pathnames in them
+  # which we rewrite here
+  lscripts="${INSTALL_ROOT}/usr/lib/x86_64-linux-gnu/libpthread.so \
+            ${INSTALL_ROOT}/usr/lib/x86_64-linux-gnu/libc.so"
+
+  # Rewrite linker scripts
+  sed -i -e 's|/usr/lib/x86_64-linux-gnu/||g'  ${lscripts}
+  sed -i -e 's|/lib/x86_64-linux-gnu/||g' ${lscripts}
+
+  # This is for chrome's ./build/linux/pkg-config-wrapper
+  # which overwrites PKG_CONFIG_PATH internally
+  SubBanner "Package Configs Symlink"
+  mkdir -p ${INSTALL_ROOT}/usr/share
+  ln -s ../lib/x86_64-linux-gnu/pkgconfig ${INSTALL_ROOT}/usr/share/pkgconfig
+
+  SubBanner "Adding an additional ld.conf include"
+  LD_SO_HACK_CONF="${INSTALL_ROOT}/etc/ld.so.conf.d/zz_hack.conf"
+  echo /usr/lib/gcc/x86_64-linux-gnu/4.6 > "$LD_SO_HACK_CONF"
+  echo /usr/lib >> "$LD_SO_HACK_CONF"
+}
+
+
+HacksAndPatchesI386() {
+  Banner "Misc Hacks & Patches"
+  # these are linker scripts with absolute pathnames in them
+  # which we rewrite here
+  lscripts="${INSTALL_ROOT}/usr/lib/i386-linux-gnu/libpthread.so \
+            ${INSTALL_ROOT}/usr/lib/i386-linux-gnu/libc.so"
+
+  # Rewrite linker scripts
+  sed -i -e 's|/usr/lib/i386-linux-gnu/||g'  ${lscripts}
+  sed -i -e 's|/lib/i386-linux-gnu/||g' ${lscripts}
+
+  # This is for chrome's ./build/linux/pkg-config-wrapper
+  # which overwrites PKG_CONFIG_PATH internally
+  SubBanner "Package Configs Symlink"
+  mkdir -p ${INSTALL_ROOT}/usr/share
+  ln -s ../lib/i386-linux-gnu/pkgconfig ${INSTALL_ROOT}/usr/share/pkgconfig
+
+  SubBanner "Adding an additional ld.conf include"
+  LD_SO_HACK_CONF="${INSTALL_ROOT}/etc/ld.so.conf.d/zz_hack.conf"
+  echo /usr/lib/gcc/i486-linux-gnu/4.6 > "$LD_SO_HACK_CONF"
+  echo /usr/lib >> "$LD_SO_HACK_CONF"
+}
+
+
+HacksAndPatchesARM() {
+  Banner "Misc Hacks & Patches"
+  # these are linker scripts with absolute pathnames in them
+  # which we rewrite here
+  lscripts="${INSTALL_ROOT}/usr/lib/arm-linux-gnueabihf/libpthread.so \
+            ${INSTALL_ROOT}/usr/lib/arm-linux-gnueabihf/libc.so"
+
+  # Rewrite linker scripts
+  sed -i -e 's|/usr/lib/arm-linux-gnueabihf/||g' ${lscripts}
+  sed -i -e 's|/lib/arm-linux-gnueabihf/||g' ${lscripts}
+
+  # This is for chrome's ./build/linux/pkg-config-wrapper
+  # which overwrites PKG_CONFIG_PATH internally
+  SubBanner "Package Configs Symlink"
+  mkdir -p ${INSTALL_ROOT}/usr/share
+  ln -s ../lib/arm-linux-gnueabihf/pkgconfig ${INSTALL_ROOT}/usr/share/pkgconfig
+}
+
+
+HacksAndPatchesMips() {
+  Banner "Misc Hacks & Patches"
+  # these are linker scripts with absolute pathnames in them
+  # which we rewrite here
+  lscripts="${INSTALL_ROOT}/usr/lib/mipsel-linux-gnu/libpthread.so \
+            ${INSTALL_ROOT}/usr/lib/mipsel-linux-gnu/libc.so"
+
+  # Rewrite linker scripts
+  sed -i -e 's|/usr/lib/mipsel-linux-gnu/||g' ${lscripts}
+  sed -i -e 's|/lib/mipsel-linux-gnu/||g' ${lscripts}
+
+  # This is for chrome's ./build/linux/pkg-config-wrapper
+  # which overwrites PKG_CONFIG_PATH internally
+  SubBanner "Package Configs Symlink"
+  mkdir -p ${INSTALL_ROOT}/usr/share
+  ln -s ../lib/mipsel-linux-gnu/pkgconfig ${INSTALL_ROOT}/usr/share/pkgconfig
+}
+
+
+InstallIntoSysroot() {
+  Banner "Install Libs And Headers Into Jail"
+
+  mkdir -p ${BUILD_DIR}/debian-packages
+  mkdir -p ${INSTALL_ROOT}
+  while (( "$#" )); do
+    local file="$1"
+    local package="${BUILD_DIR}/debian-packages/${file##*/}"
+    shift
+    local sha256sum="$1"
+    shift
+    if [ "${#sha256sum}" -ne "64" ]; then
+      echo "Bad sha256sum from package list"
+      exit 1
+    fi
+
+    Banner "Installing ${file}"
+    DownloadOrCopy ${APT_REPO}/pool/${file} ${package}
+    if [ ! -s "${package}" ] ; then
+      echo
+      echo "ERROR: bad package ${package}"
+      exit 1
+    fi
+    echo "${sha256sum}  ${package}" | sha256sum --quiet -c
+
+    SubBanner "Extracting to ${INSTALL_ROOT}"
+    dpkg --fsys-tarfile ${package}\
+      | tar -xf - --exclude=./usr/share -C ${INSTALL_ROOT}
+  done
+}
+
+
+CleanupJailSymlinks() {
+  Banner "Jail symlink cleanup"
+
+  SAVEDPWD=$(pwd)
+  cd ${INSTALL_ROOT}
+  local libdirs="lib usr/lib"
+  if [ "${ARCH}" != "MIPS" ]; then
+    libdirs+=" lib64"
+  fi
+  find $libdirs -type l -printf '%p %l\n' | while read link target; do
+    # skip links with non-absolute paths
+    echo "${target}" | grep -qs ^/ || continue
+    echo "${link}: ${target}"
+    case "${link}" in
+      usr/lib/gcc/x86_64-linux-gnu/4.*/* | usr/lib/gcc/i486-linux-gnu/4.*/* | \
+      usr/lib/gcc/arm-linux-gnueabihf/4.*/* | \
+      usr/lib/gcc/mipsel-linux-gnu/4.*/*)
+        # Relativize the symlink.
+        ln -snfv "../../../../..${target}" "${link}"
+        ;;
+      usr/lib/x86_64-linux-gnu/* | usr/lib/i386-linux-gnu/* | \
+      usr/lib/arm-linux-gnueabihf/* | usr/lib/mipsel-linux-gnu/* )
+        # Relativize the symlink.
+        ln -snfv "../../..${target}" "${link}"
+        ;;
+      usr/lib/*)
+        # Relativize the symlink.
+        ln -snfv "../..${target}" "${link}"
+        ;;
+      lib64/* | lib/*)
+        # Relativize the symlink.
+        ln -snfv "..${target}" "${link}"
+        ;;
+    esac
+  done
+
+  find $libdirs -type l -printf '%p %l\n' | while read link target; do
+    # Make sure we catch new bad links.
+    if [ ! -r "${link}" ]; then
+      echo "ERROR: FOUND BAD LINK ${link}"
+      ls -l ${link}
+      exit 1
+    fi
+  done
+  cd "$SAVEDPWD"
+}
+
+#@
+#@ BuildSysrootAmd64
+#@
+#@    Build everything and package it
+BuildSysrootAmd64() {
+  ClearInstallDir
+  local package_file="$BUILD_DIR/package_with_sha256sum_amd64"
+  GeneratePackageListAmd64 "$package_file"
+  local files_and_sha256sums="$(cat ${package_file})"
+  StripChecksumsFromPackageList "$package_file"
+  VerifyPackageFilesMatch "$package_file" "$DEBIAN_DEP_LIST_AMD64"
+  InstallIntoSysroot ${files_and_sha256sums}
+  CleanupJailSymlinks
+  HacksAndPatchesAmd64
+  CreateTarBall
+}
+
+#@
+#@ BuildSysrootI386
+#@
+#@    Build everything and package it
+BuildSysrootI386() {
+  ClearInstallDir
+  local package_file="$BUILD_DIR/package_with_sha256sum_i386"
+  GeneratePackageListI386 "$package_file"
+  local files_and_sha256sums="$(cat ${package_file})"
+  StripChecksumsFromPackageList "$package_file"
+  VerifyPackageFilesMatch "$package_file" "$DEBIAN_DEP_LIST_I386"
+  InstallIntoSysroot ${files_and_sha256sums}
+  CleanupJailSymlinks
+  HacksAndPatchesI386
+  CreateTarBall
+}
+
+#@
+#@ BuildSysrootARM
+#@
+#@    Build everything and package it
+BuildSysrootARM() {
+  ClearInstallDir
+  local package_file="$BUILD_DIR/package_with_sha256sum_arm"
+  GeneratePackageListARM "$package_file"
+  local files_and_sha256sums="$(cat ${package_file})"
+  StripChecksumsFromPackageList "$package_file"
+  VerifyPackageFilesMatch "$package_file" "$DEBIAN_DEP_LIST_ARM"
+  APT_REPO=${APR_REPO_ARM:=$APT_REPO}
+  InstallIntoSysroot ${files_and_sha256sums}
+  CleanupJailSymlinks
+  HacksAndPatchesARM
+  CreateTarBall
+}
+
+#@
+#@ BuildSysrootMips
+#@
+#@    Build everything and package it
+BuildSysrootMips() {
+  ClearInstallDir
+  local package_file="$BUILD_DIR/package_with_sha256sum_arm"
+  GeneratePackageListMips "$package_file"
+  local files_and_sha256sums="$(cat ${package_file})"
+  StripChecksumsFromPackageList "$package_file"
+  VerifyPackageFilesMatch "$package_file" "$DEBIAN_DEP_LIST_MIPS"
+  APT_REPO=${APR_REPO_MIPS:=$APT_REPO}
+  InstallIntoSysroot ${files_and_sha256sums}
+  CleanupJailSymlinks
+  HacksAndPatchesMips
+  CreateTarBall
+}
+
+#@
+#@ BuildSysrootAll
+#@
+#@    Build sysroot images for all architectures
+BuildSysrootAll() {
+  RunCommand BuildSysrootAmd64
+  RunCommand BuildSysrootI386
+  RunCommand BuildSysrootARM
+  RunCommand BuildSysrootMips
+}
+
+UploadSysroot() {
+  local rev=$1
+  if [ -z "${rev}" ]; then
+    echo "Please specify a revision to upload at."
+    exit 1
+  fi
+  set -x
+  gsutil cp -a public-read "${TARBALL}" \
+      "gs://chrome-linux-sysroot/toolchain/$rev/"
+  set +x
+}
+
+#@
+#@ UploadSysrootAmd64 <revision>
+#@
+UploadSysrootAmd64() {
+  UploadSysroot "$@"
+}
+
+#@
+#@ UploadSysrootI386 <revision>
+#@
+UploadSysrootI386() {
+  UploadSysroot "$@"
+}
+
+#@
+#@ UploadSysrootARM <revision>
+#@
+UploadSysrootARM() {
+  UploadSysroot "$@"
+}
+
+#@
+#@ UploadSysrootMips <revision>
+#@
+UploadSysrootMips() {
+  UploadSysroot "$@"
+}
+
+#@
+#@ UploadSysrootAll <revision>
+#@
+#@    Upload sysroot image for all architectures
+UploadSysrootAll() {
+  RunCommand UploadSysrootAmd64 "$@"
+  RunCommand UploadSysrootI386 "$@"
+  RunCommand UploadSysrootARM "$@"
+  RunCommand UploadSysrootMips "$@"
+}
+
+#
+# CheckForDebianGPGKeyring
+#
+#     Make sure the Debian GPG keys exist. Otherwise print a helpful message.
+#
+CheckForDebianGPGKeyring() {
+  if [ ! -e "$KEYRING_FILE" ]; then
+    echo "Debian GPG keys missing. Install the debian-archive-keyring package."
+    exit 1
+  fi
+}
+
+#
+# VerifyPackageListing
+#
+#     Verifies the downloaded Packages.bz2 file has the right checksums.
+#
+VerifyPackageListing() {
+  local file_path=$1
+  local output_file=$2
+  local release_file="${BUILD_DIR}/${RELEASE_FILE}"
+  local release_file_gpg="${BUILD_DIR}/${RELEASE_FILE_GPG}"
+  local local_keyring_file="${BUILD_DIR}/keyring.gpg"
+
+  CheckForDebianGPGKeyring
+
+  DownloadOrCopy ${RELEASE_LIST} ${release_file}
+  DownloadOrCopy ${RELEASE_LIST_GPG} ${release_file_gpg}
+  if [ ! -f "${local_keyring_file}" ]; then
+    echo "Generating keyring: ${local_keyring_file}"
+    set -x
+    cp "${KEYRING_FILE}" "${local_keyring_file}"
+    gpg --primary-keyring "${local_keyring_file}" --recv-keys 2B90D010
+    set +x
+  fi
+  echo "Verifying: ${release_file} with ${release_file_gpg}"
+  gpgv --keyring "${local_keyring_file}" "${release_file_gpg}" "${release_file}"
+
+  echo "Verifying: ${output_file}"
+  local checksums=$(grep ${file_path} ${release_file} | cut -d " " -f 2)
+  local sha256sum=$(echo ${checksums} | cut -d " " -f 3)
+
+  if [ "${#sha256sum}" -ne "64" ]; then
+    echo "Bad sha256sum from ${RELEASE_LIST}"
+    exit 1
+  fi
+
+  echo "${sha256sum}  ${output_file}" | sha256sum --quiet -c
+}
+
+#
+# GeneratePackageList
+#
+#     Looks up package names in ${BUILD_DIR}/Packages and write list of URLs
+#     to output file.
+#
+GeneratePackageList() {
+  local input_file="$1"
+  local output_file="$2"
+  echo "Updating: ${output_file} from ${input_file}"
+  /bin/rm -f "${output_file}"
+  shift
+  shift
+  for pkg in $@ ; do
+    local pkg_full=$(grep -A 1 " ${pkg}\$" "$input_file" | \
+      egrep -o "pool/.*")
+    if [ -z "${pkg_full}" ]; then
+        echo "ERROR: missing package: $pkg"
+        exit 1
+    fi
+    local pkg_nopool=$(echo "$pkg_full" | sed "s/^pool\///")
+    local sha256sum=$(grep -A 4 " ${pkg}\$" "$input_file" | \
+      grep ^SHA256: | sed 's/^SHA256: //')
+    if [ "${#sha256sum}" -ne "64" ]; then
+      echo "Bad sha256sum from Packages"
+      exit 1
+    fi
+    echo $pkg_nopool $sha256sum >> "$output_file"
+  done
+  # sort -o does an in-place sort of this file
+  sort "$output_file" -o "$output_file"
+}
+
+#@
+#@ UpdatePackageListsAmd64
+#@
+#@     Regenerate the package lists such that they contain an up-to-date
+#@     list of URLs within the Debian archive. (For amd64)
+UpdatePackageListsAmd64() {
+  GeneratePackageListAmd64 "$DEBIAN_DEP_LIST_AMD64"
+  StripChecksumsFromPackageList "$DEBIAN_DEP_LIST_AMD64"
+}
+
+#@
+#@ UpdatePackageListsI386
+#@
+#@     Regenerate the package lists such that they contain an up-to-date
+#@     list of URLs within the Debian archive. (For i386)
+UpdatePackageListsI386() {
+  GeneratePackageListI386 "$DEBIAN_DEP_LIST_I386"
+  StripChecksumsFromPackageList "$DEBIAN_DEP_LIST_I386"
+}
+
+#@
+#@ UpdatePackageListsARM
+#@
+#@     Regenerate the package lists such that they contain an up-to-date
+#@     list of URLs within the Debian archive. (For arm)
+UpdatePackageListsARM() {
+  GeneratePackageListARM "$DEBIAN_DEP_LIST_ARM"
+  StripChecksumsFromPackageList "$DEBIAN_DEP_LIST_ARM"
+}
+
+#@
+#@ UpdatePackageListsMips
+#@
+#@     Regenerate the package lists such that they contain an up-to-date
+#@     list of URLs within the Debian archive. (For arm)
+UpdatePackageListsMips() {
+  GeneratePackageListMips "$DEBIAN_DEP_LIST_MIPS"
+  StripChecksumsFromPackageList "$DEBIAN_DEP_LIST_MIPS"
+}
+
+#@
+#@ UpdatePackageListsAll
+#@
+#@    Regenerate the package lists for all architectures.
+UpdatePackageListsAll() {
+  RunCommand UpdatePackageListsAmd64
+  RunCommand UpdatePackageListsI386
+  RunCommand UpdatePackageListsARM
+  RunCommand UpdatePackageListsMips
+}
+
+RunCommand() {
+  SetEnvironmentVariables "$1"
+  SanityCheck
+  "$@"
+}
+
+if [ $# -eq 0 ] ; then
+  echo "ERROR: you must specify a mode on the commandline"
+  echo
+  Usage
+  exit 1
+elif [ "$(type -t $1)" != "function" ]; then
+  echo "ERROR: unknown function '$1'." >&2
+  echo "For help, try:"
+  echo "    $0 help"
+  exit 1
+else
+  ChangeDirectory
+  if echo $1 | grep -qs "All$"; then
+    "$@"
+  else
+    RunCommand "$@"
+  fi
+fi
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index 476476e..2c34629 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -4,14 +4,6 @@
 
 {
   '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
@@ -136,7 +128,7 @@
           ],
         },
         {
-          'target_name': 'gtk',
+          'target_name': 'gtk2',
           'type': 'none',
           'toolsets': ['host', 'target'],
           'variables': {
@@ -177,7 +169,7 @@
           ],
         },
         {
-          'target_name': 'gtkprint',
+          'target_name': 'gtkprint2',
           'type': 'none',
           'conditions': [
             ['_toolset=="target"', {
@@ -431,6 +423,74 @@
         }
       ],  # targets
     }],
+    ['use_gtk3==1', {
+      # Hide GTK3 and related dependencies when use_gtk3==0 because the user
+      # might not have the GTK3 headers yet.
+      'targets': [
+        {
+          'target_name': 'gtk3',
+          '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+-3.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': 'gtkprint3',
+          'type': 'none',
+          'conditions': [
+            ['_toolset=="target"', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags gtk+-unix-print-3.0)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other gtk+-unix-print-3.0)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l gtk+-unix-print-3.0)',
+                ],
+              },
+            }],
+          ],
+        },
+      ],
+    }],
     ['use_x11==1 and chromeos==0', {
       'targets': [
         {
@@ -511,28 +571,7 @@
         },
       ],
     }],
-    ['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', {
+    ['ozone_platform_gbm==1 or chromeos==1', {
       'targets': [
         {
           'target_name': 'libdrm',
@@ -543,6 +582,9 @@
             ],
           },
           'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other libdrm)',
+            ],
             'libraries': [
               '<!@(<(pkg-config) --libs-only-l libdrm)',
             ],
@@ -1226,5 +1268,26 @@
         }],
       ],
     },
+    {
+      'target_name': 'libffi',
+      'type': 'none',
+      'conditions': [
+        ['_toolset=="target"', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags libffi)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other libffi)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l libffi)',
+            ],
+          },
+        }],
+      ],
+    },
   ],
 }
diff --git a/build/linux/unbundle/remove_bundled_libraries.py b/build/linux/unbundle/remove_bundled_libraries.py
index 69e76f5..1cf2841 100755
--- a/build/linux/unbundle/remove_bundled_libraries.py
+++ b/build/linux/unbundle/remove_bundled_libraries.py
@@ -68,6 +68,10 @@
       if f.endswith('.gyp') or f.endswith('.gypi'):
         continue
 
+      # Same about GN files.
+      if f.endswith('.gn') or f.endswith('.gni'):
+        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
diff --git a/build/linux/unbundle/replace_gyp_files.py b/build/linux/unbundle/replace_gyp_files.py
index d06ae41..13f7ba9 100755
--- a/build/linux/unbundle/replace_gyp_files.py
+++ b/build/linux/unbundle/replace_gyp_files.py
@@ -26,7 +26,7 @@
   '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_libvpx': 'third_party/libvpx_new/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',
@@ -35,7 +35,6 @@
   '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',
diff --git a/build/linux/unbundle/speex.gyp b/build/linux/unbundle/speex.gyp
deleted file mode 100644
index 75376c8..0000000
--- a/build/linux/unbundle/speex.gyp
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2013 The Chromium 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/mac/find_sdk.py b/build/mac/find_sdk.py
index 0534766..ec1c96c 100755
--- a/build/mac/find_sdk.py
+++ b/build/mac/find_sdk.py
@@ -35,7 +35,9 @@
   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()
+  options, args = parser.parse_args()
+  if len(args) != 1:
+    parser.error('Please specify a minimum SDK version')
   min_sdk_version = args[0]
 
   job = subprocess.Popen(['xcode-select', '-print-path'],
@@ -88,3 +90,4 @@
   if sys.platform != 'darwin':
     raise Exception("This script only runs on Mac")
   print main()
+  sys.exit(0)
diff --git a/build/mac/make_more_helpers.sh b/build/mac/make_more_helpers.sh
deleted file mode 100755
index 6f5c474..0000000
--- a/build/mac/make_more_helpers.sh
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/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/tweak_info_plist.py b/build/mac/tweak_info_plist.py
index 2057bac..a6ffbca 100755
--- a/build/mac/tweak_info_plist.py
+++ b/build/mac/tweak_info_plist.py
@@ -159,7 +159,7 @@
 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')
+  components = ('full',)
   assert tuple(sorted(components)) == components
 
   components_len = len(components)
diff --git a/build/mac/verify_no_objc.sh b/build/mac/verify_no_objc.sh
deleted file mode 100755
index e18a5ea..0000000
--- a/build/mac/verify_no_objc.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/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
deleted file mode 100644
index efa5535..0000000
--- a/build/module_args/mojo.gni
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2015 The Chromium Authors. 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
deleted file mode 100644
index 8b5204c..0000000
--- a/build/module_args/v8.gni
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2014 The Chromium 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/precompile.h b/build/precompile.h
index 32c2f11..50a9b87 100644
--- a/build/precompile.h
+++ b/build/precompile.h
@@ -2,17 +2,8 @@
 // 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.
+// This file is used as a precompiled header for both C and C++ files. So
+// any C++ headers must go in the __cplusplus block below.
 
 #if defined(BUILD_PRECOMPILE_H_)
 #error You shouldn't include the precompiled header file more than once.
@@ -22,83 +13,38 @@
 
 #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 <limits.h>
 #include <math.h>
-#include <memory.h>  // 1
+#include <memory.h>
 #include <signal.h>
-#include <stdarg.h>  // 1
+#include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <time.h>  // 4
+#include <time.h>
+
+#if defined(__cplusplus)
 
 #include <algorithm>
-#include <bitset>  // 3
+#include <bitset>
 #include <cmath>
 #include <cstddef>
-#include <cstdio>  // 3
-#include <cstdlib>  // 2
+#include <cstdio>
+#include <cstdlib>
 #include <cstring>
 #include <deque>
-#include <fstream>  // 3
+#include <fstream>
 #include <functional>
-#include <iomanip>  // 2
-#include <iosfwd>  // 2
+#include <iomanip>
+#include <iosfwd>
 #include <iterator>
 #include <limits>
 #include <list>
 #include <map>
-#include <numeric>  // 2
+#include <numeric>
 #include <ostream>
 #include <queue>
 #include <set>
@@ -107,3 +53,5 @@
 #include <string>
 #include <utility>
 #include <vector>
+
+#endif  // __cplusplus
diff --git a/build/sanitizers/OWNERS b/build/sanitizers/OWNERS
index 0be2be8..3810da5 100644
--- a/build/sanitizers/OWNERS
+++ b/build/sanitizers/OWNERS
@@ -1,4 +1,5 @@
 glider@chromium.org
 earthdok@chromium.org
+eugenis@chromium.org
 per-file tsan_suppressions.cc=*
 per-file lsan_suppressions.cc=*
diff --git a/build/sanitizers/lsan_suppressions.cc b/build/sanitizers/lsan_suppressions.cc
index ac2defa..d1c9d22 100644
--- a/build/sanitizers/lsan_suppressions.cc
+++ b/build/sanitizers/lsan_suppressions.cc
@@ -25,9 +25,6 @@
 // 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"
@@ -51,29 +48,11 @@
 // 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"
+// http://crbug.com/431213, http://crbug.com/416665
 "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 swrast_dri.so. http://crbug.com/540042
+"leak:swrast_dri.so\n"
 
 // ================ Leaks in Chromium code ================
 // PLEASE DO NOT ADD SUPPRESSIONS FOR NEW LEAKS.
diff --git a/build/sanitizers/sanitizer_options.cc b/build/sanitizers/sanitizer_options.cc
index a659a22..b06ec7e 100644
--- a/build/sanitizers/sanitizer_options.cc
+++ b/build/sanitizers/sanitizer_options.cc
@@ -12,8 +12,9 @@
 #include <string.h>
 #endif  // ADDRESS_SANITIZER && OS_MACOSX
 
-#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
-    defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER)
+#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) ||  \
+    defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
+    defined(UNDEFINED_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
@@ -25,12 +26,10 @@
 // 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")))  \
+#define SANITIZER_HOOK_ATTRIBUTE                                           \
+  extern "C"                                                               \
+  __attribute__((no_sanitize("address", "memory", "thread", "undefined"))) \
+  __attribute__((visibility("default")))                                   \
   __attribute__((used))
 #endif
 
@@ -129,7 +128,7 @@
 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/../../ ";
+    "strict_memcmp=0 strip_path_prefix=Release/../../ ";
 
 SANITIZER_HOOK_ATTRIBUTE const char *__tsan_default_options() {
   return kTsanDefaultOptions;
@@ -143,6 +142,21 @@
 
 #endif  // THREAD_SANITIZER && OS_LINUX
 
+#if defined(MEMORY_SANITIZER)
+// Default options for MemorySanitizer:
+//   intercept_memcmp=0 - do not detect uninitialized memory in memcmp() calls.
+//     Pending cleanup, see http://crbug.com/523428
+//   strip_path_prefix=Release/../../ - prefixes up to and including this
+//     substring will be stripped from source file paths in symbolized reports.
+const char kMsanDefaultOptions[] =
+    "intercept_memcmp=0 strip_path_prefix=Release/../../ ";
+
+SANITIZER_HOOK_ATTRIBUTE const char *__msan_default_options() {
+  return kMsanDefaultOptions;
+}
+
+#endif  // MEMORY_SANITIZER
+
 #if defined(LEAK_SANITIZER)
 // Default options for LeakSanitizer:
 //   print_suppressions=1 - print the list of matched suppressions.
@@ -162,3 +176,14 @@
 }
 
 #endif  // LEAK_SANITIZER
+
+#if defined(UNDEFINED_SANITIZER)
+// Default options for UndefinedBehaviorSanitizer:
+//   print_stacktrace=1 - print the stacktrace when UBSan reports an error.
+const char kUbsanDefaultOptions[] = "print_stacktrace=1";
+
+SANITIZER_HOOK_ATTRIBUTE const char* __ubsan_default_options() {
+  return kUbsanDefaultOptions;
+}
+
+#endif  // UNDEFINED_SANITIZER
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index e053a16..d0e41e5 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -50,7 +50,7 @@
 "race:base/threading/watchdog.cc\n"
 
 // http://crbug.com/157586
-"race:third_party/libvpx/source/libvpx/vp8/decoder/threading.c\n"
+"race:third_party/libvpx_new/source/libvpx/vp8/decoder/threading.c\n"
 
 // http://crbug.com/158718
 "race:third_party/ffmpeg/libavcodec/pthread.c\n"
@@ -62,8 +62,8 @@
 "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"
+"race:third_party/libvpx_new/source/libvpx/vp8/encoder/*\n"
+"race:third_party/libvpx_new/source/libvpx/vp9/encoder/*\n"
 
 // http://crbug.com/189177
 "race:thread_manager\n"
@@ -125,34 +125,21 @@
 // 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"
@@ -170,9 +157,6 @@
 // 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"
@@ -252,11 +236,6 @@
 "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"
 
@@ -272,12 +251,6 @@
 // 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"
@@ -285,8 +258,8 @@
 // http://crbug.com/415472
 "deadlock:base::trace_event::TraceLog::GetCategoryGroupEnabled\n"
 
-// http://crbug.com/425057
-"deadlock:webrtc::ViEChannelManagerScoped::ViEChannelManagerScoped\n"
+// http://crbug.com/490856
+"deadlock:content::TracingControllerImpl::SetEnabledOnFileThread\n"
 
 // http://crbug.com/417193
 // Suppressing both AudioContext.{cpp,h}.
@@ -301,14 +274,13 @@
 // https://crbug.com/448203
 "race:blink::RemoteFrame::detach\n"
 
-// https://crbug.com/454652
-"race:net::NetworkChangeNotifier::SetTestNotificationsOnly\n"
-
+// Lock inversion in third party code, won't fix.
 // https://crbug.com/455638
 "deadlock:dbus::Bus::ShutdownAndBlock\n"
 
 // https://crbug.com/455665
 "race:mojo::common::*::tick_clock\n"
+"race:mojo::common::internal::NowTicks\n"
 
 // https://crbug.com/459429
 "race:randomnessPid\n"
@@ -316,6 +288,9 @@
 // https://crbug.com/454655
 "race:content::BrowserTestBase::PostTaskToInProcessRendererAndWait\n"
 
+// https://crbug.com/539315
+"race:MojoCreateMessagePipe\n"
+
 // End of suppressions.
 ;  // Please keep this semicolon.
 
diff --git a/build/secondary/testing/gtest/BUILD.gn b/build/secondary/testing/gtest/BUILD.gn
index a20a09d..8e5cdcc 100644
--- a/build/secondary/testing/gtest/BUILD.gn
+++ b/build/secondary/testing/gtest/BUILD.gn
@@ -58,6 +58,15 @@
   defines = [ "UNIT_TEST" ]
 }
 
+config("gtest_warnings") {
+  if (is_win && is_clang) {
+    # The Mutex constructor initializer list in gtest-port.cc is incorrectly
+    # ordered. See
+    # https://groups.google.com/d/msg/googletestframework/S5uSV8L2TX8/U1FaTDa6J6sJ.
+    cflags = [ "-Wno-reorder" ]
+  }
+}
+
 static_library("gtest") {
   # TODO http://crbug.com/412064 enable this flag all the time.
   testonly = !is_component_build
@@ -96,12 +105,23 @@
     "src/gtest.cc",
   ]
 
-  if (is_mac) {
+  if (is_mac || is_ios) {
+    if (is_ios) {
+      set_sources_assignment_filter([])
+    }
     sources += [
       "../gtest_mac.h",
       "../gtest_mac.mm",
       "../platform_test_mac.mm",
     ]
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
+  if (is_ios) {
+    sources += [
+      "../coverage_util_ios.cc",
+      "../coverage_util_ios.h",
+    ]
   }
 
   include_dirs = [ "." ]
@@ -110,7 +130,12 @@
   public_configs = [ ":gtest_direct_config" ]
 
   configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [ "//build/config/compiler:no_chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+
+    # Must be after no_chromium_code for warning flags to be ordered correctly.
+    ":gtest_warnings",
+  ]
 }
 
 source_set("gtest_main") {
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn
index 099b892..fa2f67a 100644
--- a/build/secondary/third_party/android_tools/BUILD.gn
+++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -28,13 +28,22 @@
   jar_path = "$android_sdk/uiautomator.jar"
 }
 
+android_java_prebuilt("android_support_annotations_javalib") {
+  jar_path = "$android_sdk_root/extras/android/support/annotations/android-support-annotations.jar"
+}
+
+java_prebuilt("android_support_multidex_java") {
+  supports_android = true
+  jar_path = "$android_sdk_root/extras/android/support/multidex/library/libs/android-support-multidex.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
+  v14_skip = true
   resource_dirs =
       [ "$android_sdk_root/extras/android/support/v7/appcompat/res" ]
   custom_package = "android.support.v7.appcompat"
@@ -48,7 +57,7 @@
 }
 
 android_resources("android_support_v7_mediarouter_resources") {
-  v14_verify_only = true
+  v14_skip = true
   resource_dirs =
       [ "$android_sdk_root/extras/android/support/v7/mediarouter/res" ]
   deps = [
@@ -59,28 +68,45 @@
 
 android_java_prebuilt("android_support_v7_mediarouter_java") {
   deps = [
-    ":android_support_v7_mediarouter_resources",
     ":android_support_v7_appcompat_java",
+    ":android_support_v7_mediarouter_resources",
   ]
   jar_path = "$android_sdk_root/extras/android/support/v7/mediarouter/libs/android-support-v7-mediarouter.jar"
 }
 
+android_resources("android_support_v7_recyclerview_resources") {
+  v14_skip = true
+  resource_dirs =
+      [ "$android_sdk_root/extras/android/support/v7/recyclerview/res" ]
+  custom_package = "android.support.v7.recyclerview"
+}
+
 android_java_prebuilt("android_support_v7_recyclerview_java") {
   deps = [
     ":android_support_v7_appcompat_java",
+    ":android_support_v7_recyclerview_resources",
   ]
   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
+  v14_skip = 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",
+    ":android_support_v7_mediarouter_java",
     ":google_play_services_default_resources",
+    ":legacy_http_javalib",
   ]
+  proguard_preprocess = true
+  proguard_config = "//third_party/android_tools/proguard.flags"
   jar_path = "$android_sdk_root/extras/google/google_play_services/libproject/google-play-services_lib/libs/google-play-services.jar"
 }
+
+# TODO(jbudorick): Remove this once net_java_test_support no longer needs it.
+android_java_prebuilt("legacy_http_javalib") {
+  jar_path = "$android_sdk/optional/org.apache.http.legacy.jar"
+}
diff --git a/build/secondary/third_party/cacheinvalidation/BUILD.gn b/build/secondary/third_party/cacheinvalidation/BUILD.gn
deleted file mode 100644
index 17e4d1c..0000000
--- a/build/secondary/third_party/cacheinvalidation/BUILD.gn
+++ /dev/null
@@ -1,146 +0,0 @@
-# Copyright 2014 The Chromium 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
deleted file mode 100644
index 3bbb844..0000000
--- a/build/secondary/third_party/cacheinvalidation/src/google/cacheinvalidation/BUILD.gn
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2014 The Chromium 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/crashpad/crashpad/client/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/client/BUILD.gn
new file mode 100644
index 0000000..4ebb22d
--- /dev/null
+++ b/build/secondary/third_party/crashpad/crashpad/client/BUILD.gn
@@ -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.
+
+config("client_config") {
+  include_dirs = [ ".." ]
+}
+
+source_set("client") {
+  sources = [
+    "crash_report_database.cc",
+    "crash_report_database.h",
+    "crash_report_database_mac.mm",
+    "crash_report_database_win.cc",
+    "crashpad_client.h",
+    "crashpad_client_mac.cc",
+    "crashpad_client_win.cc",
+    "crashpad_info.cc",
+    "crashpad_info.h",
+    "prune_crash_reports.cc",
+    "prune_crash_reports.h",
+    "settings.cc",
+    "settings.h",
+    "simple_string_dictionary.cc",
+    "simple_string_dictionary.h",
+    "simulate_crash.h",
+    "simulate_crash_mac.cc",
+    "simulate_crash_mac.h",
+    "simulate_crash_win.h",
+  ]
+
+  if (is_mac) {
+    sources += [
+      "capture_context_mac.S",
+      "capture_context_mac.h",
+    ]
+  }
+
+  public_configs = [ ":client_config" ]
+
+  deps = [
+    "//base",
+    "//third_party/crashpad/crashpad/compat",
+    "//third_party/crashpad/crashpad/util",
+  ]
+
+  if (is_win) {
+    libs = [ "rpcrt4.lib" ]
+  }
+}
diff --git a/build/secondary/third_party/crashpad/crashpad/compat/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/compat/BUILD.gn
new file mode 100644
index 0000000..904fa54
--- /dev/null
+++ b/build/secondary/third_party/crashpad/crashpad/compat/BUILD.gn
@@ -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.
+
+config("compat_config") {
+  if (is_win) {
+    include_dirs = [ "win" ]
+  } else if (is_mac) {
+    include_dirs = [ "mac" ]
+  }
+}
+
+source_set("compat") {
+  sources = []
+  if (is_mac) {
+    sources += [
+      "mac/AvailabilityMacros.h",
+      "mac/kern/exc_resource.h",
+      "mac/mach-o/getsect.cc",
+      "mac/mach-o/getsect.h",
+      "mac/mach-o/loader.h",
+      "mac/mach/mach.h",
+      "mac/sys/resource.h",
+    ]
+  } else {
+    sources += [ "non_mac/mach/mach.h" ]
+  }
+
+  if (is_win) {
+    sources += [
+      "win/getopt.h",
+      "win/strings.cc",
+      "win/strings.h",
+      "win/sys/types.h",
+      "win/time.cc",
+      "win/time.h",
+      "win/winnt.h",
+    ]
+  } else {
+    sources += [
+      "non_win/dbghelp.h",
+      "non_win/minwinbase.h",
+      "non_win/timezoneapi.h",
+      "non_win/verrsrc.h",
+      "non_win/windows.h",
+      "non_win/winnt.h",
+    ]
+  }
+
+  public_configs = [ ":compat_config" ]
+
+  deps = []
+  if (is_mac) {
+    deps += [ "//third_party/crashpad/crashpad/third_party/apple_cctools" ]
+  } else if (is_win) {
+    deps += [ "//third_party/crashpad/crashpad/third_party/getopt" ]
+  }
+}
diff --git a/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn
new file mode 100644
index 0000000..9ad3464
--- /dev/null
+++ b/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn
@@ -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.
+
+source_set("handler_lib") {
+  sources = [
+    "crash_report_upload_thread.cc",
+    "crash_report_upload_thread.h",
+    "handler_main.cc",
+    "handler_main.h",
+    "mac/crash_report_exception_handler.cc",
+    "mac/crash_report_exception_handler.h",
+    "mac/exception_handler_server.cc",
+    "mac/exception_handler_server.h",
+    "win/crash_report_exception_handler.cc",
+    "win/crash_report_exception_handler.h",
+  ]
+
+  include_dirs = [ ".." ]
+
+  deps = [
+    "../compat",
+    "../minidump",
+    "../snapshot",
+    "../tools:tool_support",
+    "//base",
+  ]
+
+  if (is_win) {
+    cflags = [ "/wd4201" ]
+  }
+}
+
+executable("crashpad_handler") {
+  sources = [
+    "main.cc",
+  ]
+
+  include_dirs = [ ".." ]
+
+  deps = [
+    ":handler_lib",
+    "../compat",
+    "//base",
+  ]
+}
diff --git a/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn
new file mode 100644
index 0000000..f23aa4d
--- /dev/null
+++ b/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn
@@ -0,0 +1,65 @@
+# Copyright 2015 The Chromium 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("minidump") {
+  deps = [
+    "../compat",
+    "../snapshot",
+    "../util",
+    "//base",
+  ]
+
+  include_dirs = [ ".." ]
+
+  if (is_win) {
+    cflags = [
+      "/wd4201",
+      "/wd4324",
+    ]
+  }
+
+  sources = [
+    "minidump_context.h",
+    "minidump_context_writer.cc",
+    "minidump_context_writer.h",
+    "minidump_crashpad_info_writer.cc",
+    "minidump_crashpad_info_writer.h",
+    "minidump_exception_writer.cc",
+    "minidump_exception_writer.h",
+    "minidump_extensions.cc",
+    "minidump_extensions.h",
+    "minidump_file_writer.cc",
+    "minidump_file_writer.h",
+    "minidump_handle_writer.cc",
+    "minidump_handle_writer.h",
+    "minidump_memory_info_writer.cc",
+    "minidump_memory_info_writer.h",
+    "minidump_memory_writer.cc",
+    "minidump_memory_writer.h",
+    "minidump_misc_info_writer.cc",
+    "minidump_misc_info_writer.h",
+    "minidump_module_crashpad_info_writer.cc",
+    "minidump_module_crashpad_info_writer.h",
+    "minidump_module_writer.cc",
+    "minidump_module_writer.h",
+    "minidump_rva_list_writer.cc",
+    "minidump_rva_list_writer.h",
+    "minidump_simple_string_dictionary_writer.cc",
+    "minidump_simple_string_dictionary_writer.h",
+    "minidump_stream_writer.cc",
+    "minidump_stream_writer.h",
+    "minidump_string_writer.cc",
+    "minidump_string_writer.h",
+    "minidump_system_info_writer.cc",
+    "minidump_system_info_writer.h",
+    "minidump_thread_id_map.cc",
+    "minidump_thread_id_map.h",
+    "minidump_thread_writer.cc",
+    "minidump_thread_writer.h",
+    "minidump_writable.cc",
+    "minidump_writable.h",
+    "minidump_writer_util.cc",
+    "minidump_writer_util.h",
+  ]
+}
diff --git a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
new file mode 100644
index 0000000..aa8443a
--- /dev/null
+++ b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
@@ -0,0 +1,103 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("snapshot") {
+  deps = [
+    "../client",
+    "../compat",
+    "../util",
+    "//base",
+  ]
+
+  include_dirs = [ ".." ]
+
+  if (is_win) {
+    cflags = [ "/wd4201" ]
+    libs = [ "powrprof.lib" ]
+  }
+
+  sources = [
+    "cpu_architecture.h",
+    "cpu_context.cc",
+    "cpu_context.h",
+    "crashpad_info_client_options.cc",
+    "crashpad_info_client_options.h",
+    "exception_snapshot.h",
+    "handle_snapshot.cc",
+    "handle_snapshot.h",
+    "mac/cpu_context_mac.cc",
+    "mac/cpu_context_mac.h",
+    "mac/exception_snapshot_mac.cc",
+    "mac/exception_snapshot_mac.h",
+    "mac/mach_o_image_annotations_reader.cc",
+    "mac/mach_o_image_annotations_reader.h",
+    "mac/mach_o_image_reader.cc",
+    "mac/mach_o_image_reader.h",
+    "mac/mach_o_image_segment_reader.cc",
+    "mac/mach_o_image_segment_reader.h",
+    "mac/mach_o_image_symbol_table_reader.cc",
+    "mac/mach_o_image_symbol_table_reader.h",
+    "mac/memory_snapshot_mac.cc",
+    "mac/memory_snapshot_mac.h",
+    "mac/module_snapshot_mac.cc",
+    "mac/module_snapshot_mac.h",
+    "mac/process_reader.cc",
+    "mac/process_reader.h",
+    "mac/process_snapshot_mac.cc",
+    "mac/process_snapshot_mac.h",
+    "mac/process_types.cc",
+    "mac/process_types.h",
+    "mac/process_types/all.proctype",
+    "mac/process_types/crashpad_info.proctype",
+    "mac/process_types/crashreporterclient.proctype",
+    "mac/process_types/custom.cc",
+    "mac/process_types/dyld_images.proctype",
+    "mac/process_types/flavors.h",
+    "mac/process_types/internal.h",
+    "mac/process_types/loader.proctype",
+    "mac/process_types/nlist.proctype",
+    "mac/process_types/traits.h",
+    "mac/system_snapshot_mac.cc",
+    "mac/system_snapshot_mac.h",
+    "mac/thread_snapshot_mac.cc",
+    "mac/thread_snapshot_mac.h",
+    "memory_snapshot.h",
+    "minidump/minidump_simple_string_dictionary_reader.cc",
+    "minidump/minidump_simple_string_dictionary_reader.h",
+    "minidump/minidump_string_list_reader.cc",
+    "minidump/minidump_string_list_reader.h",
+    "minidump/minidump_string_reader.cc",
+    "minidump/minidump_string_reader.h",
+    "minidump/module_snapshot_minidump.cc",
+    "minidump/module_snapshot_minidump.h",
+    "minidump/process_snapshot_minidump.cc",
+    "minidump/process_snapshot_minidump.h",
+    "module_snapshot.h",
+    "process_snapshot.h",
+    "system_snapshot.h",
+    "thread_snapshot.h",
+    "win/cpu_context_win.cc",
+    "win/cpu_context_win.h",
+    "win/exception_snapshot_win.cc",
+    "win/exception_snapshot_win.h",
+    "win/memory_map_region_snapshot_win.cc",
+    "win/memory_map_region_snapshot_win.h",
+    "win/memory_snapshot_win.cc",
+    "win/memory_snapshot_win.h",
+    "win/module_snapshot_win.cc",
+    "win/module_snapshot_win.h",
+    "win/pe_image_annotations_reader.cc",
+    "win/pe_image_annotations_reader.h",
+    "win/pe_image_reader.cc",
+    "win/pe_image_reader.h",
+    "win/process_reader_win.cc",
+    "win/process_reader_win.h",
+    "win/process_snapshot_win.cc",
+    "win/process_snapshot_win.h",
+    "win/system_snapshot_win.cc",
+    "win/system_snapshot_win.h",
+    "win/thread_snapshot_win.cc",
+    "win/thread_snapshot_win.h",
+  ]
+}
diff --git a/build/secondary/third_party/crashpad/crashpad/third_party/apple_cctools/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/third_party/apple_cctools/BUILD.gn
new file mode 100644
index 0000000..c025056
--- /dev/null
+++ b/build/secondary/third_party/crashpad/crashpad/third_party/apple_cctools/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright 2015 The Chromium 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("apple_cctools_config") {
+  include_dirs = [ "../.." ]
+}
+
+source_set("apple_cctools") {
+  sources = [
+    "cctools/include/mach-o/getsect.h",
+    "cctools/libmacho/getsecbyname.c",
+  ]
+  public_configs = [ ":apple_cctools_config" ]
+}
diff --git a/build/secondary/third_party/crashpad/crashpad/third_party/getopt/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/third_party/getopt/BUILD.gn
new file mode 100644
index 0000000..3edcfda
--- /dev/null
+++ b/build/secondary/third_party/crashpad/crashpad/third_party/getopt/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2014 The Chromium 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("getopt") {
+  sources = [
+    "getopt.cc",
+    "getopt.h",
+  ]
+}
diff --git a/build/secondary/third_party/crashpad/crashpad/tools/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/tools/BUILD.gn
new file mode 100644
index 0000000..94fe0b4
--- /dev/null
+++ b/build/secondary/third_party/crashpad/crashpad/tools/BUILD.gn
@@ -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.
+
+source_set("tool_support") {
+  deps = [
+    "//base",
+  ]
+
+  include_dirs = [ ".." ]
+
+  if (is_win) {
+    cflags = [ "/wd4201" ]
+  }
+
+  sources = [
+    "tool_support.cc",
+    "tool_support.h",
+  ]
+}
diff --git a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
new file mode 100644
index 0000000..9429597
--- /dev/null
+++ b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
@@ -0,0 +1,232 @@
+# Copyright 2015 The Chromium 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_mac) {
+  import("//build/config/sysroot.gni")
+}
+
+# Allows the source set to inject ldflags for targets that link to it.
+config("util_link_config") {
+  if (is_mac) {
+    ldflags = [ "/usr/lib/libbsm.dylib" ]
+  }
+}
+
+if (is_mac) {
+  action_foreach("mig") {
+    script = "mach/mig.py"
+    sources = [
+      "$sysroot/usr/include/mach/exc.defs",
+      "$sysroot/usr/include/mach/mach_exc.defs",
+      "$sysroot/usr/include/mach/notify.defs",
+      "mach/child_port.defs",
+    ]
+
+    outputs = [
+      "$target_gen_dir/mach/{{source_name_part}}User.c",
+      "$target_gen_dir/mach/{{source_name_part}}Server.c",
+      "$target_gen_dir/mach/{{source_name_part}}.h",
+      "$target_gen_dir/mach/{{source_name_part}}Server.h",
+    ]
+
+    args = [ "{{source}}" ]
+    args += rebase_path(outputs, root_build_dir)
+  }
+}
+
+source_set("util") {
+  sources = [
+    "file/file_io.cc",
+    "file/file_io.h",
+    "file/file_io_posix.cc",
+    "file/file_io_win.cc",
+    "file/file_reader.cc",
+    "file/file_reader.h",
+    "file/file_seeker.cc",
+    "file/file_seeker.h",
+    "file/file_writer.cc",
+    "file/file_writer.h",
+    "file/string_file.cc",
+    "file/string_file.h",
+    "mac/checked_mach_address_range.h",
+    "mac/launchd.h",
+    "mac/launchd.mm",
+    "mac/mac_util.cc",
+    "mac/mac_util.h",
+    "mac/service_management.cc",
+    "mac/service_management.h",
+    "mac/xattr.cc",
+    "mac/xattr.h",
+    "misc/clock.h",
+    "misc/clock_mac.cc",
+    "misc/clock_posix.cc",
+    "misc/clock_win.cc",
+    "misc/implicit_cast.h",
+    "misc/initialization_state.h",
+    "misc/initialization_state_dcheck.cc",
+    "misc/initialization_state_dcheck.h",
+    "misc/pdb_structures.cc",
+    "misc/pdb_structures.h",
+    "misc/random_string.cc",
+    "misc/random_string.h",
+    "misc/scoped_forbid_return.cc",
+    "misc/scoped_forbid_return.h",
+    "misc/symbolic_constants_common.h",
+    "misc/tri_state.h",
+    "misc/uuid.cc",
+    "misc/uuid.h",
+    "net/http_body.cc",
+    "net/http_body.h",
+    "net/http_headers.cc",
+    "net/http_headers.h",
+    "net/http_multipart_builder.cc",
+    "net/http_multipart_builder.h",
+    "net/http_transport.cc",
+    "net/http_transport.h",
+    "net/http_transport_mac.mm",
+    "net/http_transport_win.cc",
+    "numeric/checked_address_range.cc",
+    "numeric/checked_address_range.h",
+    "numeric/checked_range.h",
+    "numeric/in_range_cast.h",
+    "numeric/int128.h",
+    "numeric/safe_assignment.h",
+    "posix/close_multiple.cc",
+    "posix/close_multiple.h",
+    "posix/close_stdio.cc",
+    "posix/close_stdio.h",
+    "posix/drop_privileges.cc",
+    "posix/drop_privileges.h",
+    "posix/process_info.h",
+    "posix/process_info_mac.cc",
+    "posix/symbolic_constants_posix.cc",
+    "posix/symbolic_constants_posix.h",
+    "stdlib/cxx.h",
+    "stdlib/map_insert.h",
+    "stdlib/objc.h",
+    "stdlib/pointer_container.h",
+    "stdlib/string_number_conversion.cc",
+    "stdlib/string_number_conversion.h",
+    "stdlib/strlcpy.cc",
+    "stdlib/strlcpy.h",
+    "stdlib/strnlen.cc",
+    "stdlib/strnlen.h",
+    "string/split_string.cc",
+    "string/split_string.h",
+    "synchronization/semaphore.h",
+    "synchronization/semaphore_mac.cc",
+    "synchronization/semaphore_posix.cc",
+    "synchronization/semaphore_win.cc",
+    "thread/thread.cc",
+    "thread/thread.h",
+    "thread/thread_log_messages.cc",
+    "thread/thread_log_messages.h",
+    "thread/thread_posix.cc",
+    "thread/thread_win.cc",
+    "win/address_types.h",
+    "win/capture_context.asm",
+    "win/capture_context.h",
+    "win/checked_win_address_range.h",
+    "win/command_line.cc",
+    "win/command_line.h",
+    "win/critical_section_with_debug_info.cc",
+    "win/critical_section_with_debug_info.h",
+    "win/exception_handler_server.cc",
+    "win/exception_handler_server.h",
+    "win/get_function.cc",
+    "win/get_function.h",
+    "win/handle.cc",
+    "win/handle.h",
+    "win/module_version.cc",
+    "win/module_version.h",
+    "win/nt_internals.cc",
+    "win/nt_internals.h",
+    "win/ntstatus_logging.cc",
+    "win/ntstatus_logging.h",
+    "win/process_info.cc",
+    "win/process_info.h",
+    "win/process_structs.h",
+    "win/registration_protocol_win.cc",
+    "win/registration_protocol_win.h",
+    "win/scoped_handle.cc",
+    "win/scoped_handle.h",
+    "win/scoped_local_alloc.cc",
+    "win/scoped_local_alloc.h",
+    "win/scoped_process_suspend.cc",
+    "win/scoped_process_suspend.h",
+    "win/time.cc",
+    "win/time.h",
+    "win/xp_compat.h",
+  ]
+
+  if (is_mac) {
+    # mach/ are not globally filtered.
+    sources += [
+      "mach/child_port_handshake.cc",
+      "mach/child_port_handshake.h",
+      "mach/child_port_server.cc",
+      "mach/child_port_server.h",
+      "mach/child_port_types.h",
+      "mach/composite_mach_message_server.cc",
+      "mach/composite_mach_message_server.h",
+      "mach/exc_client_variants.cc",
+      "mach/exc_client_variants.h",
+      "mach/exc_server_variants.cc",
+      "mach/exc_server_variants.h",
+      "mach/exception_behaviors.cc",
+      "mach/exception_behaviors.h",
+      "mach/exception_ports.cc",
+      "mach/exception_ports.h",
+      "mach/exception_types.cc",
+      "mach/exception_types.h",
+      "mach/mach_extensions.cc",
+      "mach/mach_extensions.h",
+      "mach/mach_message.cc",
+      "mach/mach_message.h",
+      "mach/mach_message_server.cc",
+      "mach/mach_message_server.h",
+      "mach/notify_server.cc",
+      "mach/notify_server.h",
+      "mach/scoped_task_suspend.cc",
+      "mach/scoped_task_suspend.h",
+      "mach/symbolic_constants_mach.cc",
+      "mach/symbolic_constants_mach.h",
+      "mach/task_for_pid.cc",
+      "mach/task_for_pid.h",
+      "mach/task_memory.cc",
+      "mach/task_memory.h",
+    ]
+  }
+
+  # Include files from here and generated files starting with "util".
+  include_dirs = [
+    "..",
+    "$root_gen_dir/third_party/crashpad/crashpad",
+  ]
+
+  all_dependent_configs = [ ":util_link_config" ]
+
+  deps = [
+    "//base",
+    "//third_party/crashpad/crashpad/compat",
+  ]
+
+  if (is_win) {
+    libs = [
+      "rpcrt4.lib",
+      "winhttp.lib",
+    ]
+    cflags = [ "/wd4201" ]  # nonstandard extension used : nameless struct/union.
+
+    # TODO(GYP) UseSafeExceptionHandlers masm rule.
+  } else if (is_mac) {
+    sources += get_target_outputs(":mig")
+    deps += [ ":mig" ]
+    libs = [
+      "CoreFoundation.framework",
+      "Foundation.framework",
+      "IOKit.framework",
+    ]
+  }
+}
diff --git a/build/secondary/third_party/freetype/BUILD.gn b/build/secondary/third_party/freetype/BUILD.gn
deleted file mode 100644
index 96e50f3..0000000
--- a/build/secondary/third_party/freetype/BUILD.gn
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright 2014 The Chromium 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
index bf35d07..6be39fe 100644
--- a/build/secondary/third_party/libjpeg_turbo/BUILD.gn
+++ b/build/secondary/third_party/libjpeg_turbo/BUILD.gn
@@ -5,6 +5,7 @@
 # Do not use the targets in this file unless you need a certain libjpeg
 # implementation. Use the meta target //third_party:jpeg instead.
 
+import("//build/config/sanitizers/sanitizers.gni")
 if (current_cpu == "arm") {
   import("//build/config/arm.gni")
 }
@@ -198,14 +199,11 @@
 
   # 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) {
+  if (is_msan) {
     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
deleted file mode 100644
index 8b9647c..0000000
--- a/build/secondary/third_party/libsrtp/BUILD.gn
+++ /dev/null
@@ -1,339 +0,0 @@
-# Copyright 2014 The Chromium 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
index 25d449e..8d152e9 100644
--- a/build/secondary/third_party/nss/BUILD.gn
+++ b/build/secondary/third_party/nss/BUILD.gn
@@ -31,7 +31,7 @@
       "nspr/lib/libc/include",
     ]
 
-    if (component_mode != "shared_library") {
+    if (!is_component_build) {
       defines += [ "NSPR_STATIC" ]
     }
   }
@@ -220,6 +220,9 @@
     configs += [
       "//build/config/compiler:no_chromium_code",
       "//build/config/compiler:no_size_t_to_int_warning",
+
+      # nspr passes "const char*" through "void*".
+      "//build/config/compiler:no_incompatible_pointer_warnings",
     ]
 
     cflags = []
@@ -326,9 +329,6 @@
         # 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",
       ]
@@ -355,7 +355,7 @@
       public_deps += [ ":nssckbi" ]
     }
 
-    if (component_mode == "shared_library") {
+    if (is_component_build) {
       if (is_mac) {
         ldflags = [ "-all_load" ]
       } else if (is_win) {
@@ -885,6 +885,9 @@
     configs += [
       "//build/config/compiler:no_chromium_code",
       "//build/config/compiler:no_size_t_to_int_warning",
+
+      # nss passes "const char*" through "void*".
+      "//build/config/compiler:no_incompatible_pointer_warnings",
     ]
     public_configs = [ ":nss_static_config" ]
 
@@ -910,7 +913,6 @@
     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",
@@ -1094,7 +1096,7 @@
       defines += [ "NSS_DISABLE_ROOT_CERTS" ]
     }
 
-    if (current_cpu == "x64" && !is_win) {
+    if (current_cpu == "x64" && !is_win && !is_ios) {
       sources -= [
         "nss/lib/freebl/chacha20/chacha20.c",
         "nss/lib/freebl/poly1305/poly1305.c",
@@ -1173,6 +1175,7 @@
       # Not Windows.
       sources -= [
         # mpi_x86_asm.c contains MSVC inline assembly code.
+        "nss/lib/freebl/intel-aes-x86-masm.asm",
         "nss/lib/freebl/mpi/mpi_x86_asm.c",
       ]
     }
@@ -1182,9 +1185,6 @@
         # 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",
 
diff --git a/build/secondary/tools/grit/BUILD.gn b/build/secondary/tools/grit/BUILD.gn
deleted file mode 100644
index 660bf1b..0000000
--- a/build/secondary/tools/grit/BUILD.gn
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2014 The Chromium Authors. 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
deleted file mode 100644
index 35bbed3..0000000
--- a/build/secondary/tools/grit/grit_rule.gni
+++ /dev/null
@@ -1,468 +0,0 @@
-# Copyright 2014 The Chromium 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
deleted file mode 100644
index 1030674..0000000
--- a/build/secondary/tools/grit/repack.gni
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2014 The Chromium Authors. All 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
deleted file mode 100644
index d43d4b8..0000000
--- a/build/secondary/tools/grit/stamp_grit_sources.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2014 The Chromium Authors. 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/symlink.py b/build/symlink.py
index aade2f8..75a3e4e 100755
--- a/build/symlink.py
+++ b/build/symlink.py
@@ -9,6 +9,7 @@
 import errno
 import optparse
 import os.path
+import shutil
 import sys
 
 
@@ -25,11 +26,16 @@
   sources = args[:-1]
   for s in sources:
     t = os.path.join(target, os.path.basename(s))
+    if len(sources) == 1 and not os.path.isdir(target):
+      t = target
     try:
       os.symlink(s, t)
     except OSError, e:
       if e.errno == errno.EEXIST and options.force:
-        os.remove(t)
+        if os.path.isdir(t):
+          shutil.rmtree(t, ignore_errors=True)
+        else:
+          os.remove(t)
         os.symlink(s, t)
       else:
         raise
diff --git a/build/toolchain/android/BUILD.gn b/build/toolchain/android/BUILD.gn
index f7f47ff..313e609 100644
--- a/build/toolchain/android/BUILD.gn
+++ b/build/toolchain/android/BUILD.gn
@@ -3,9 +3,6 @@
 # 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
@@ -36,53 +33,45 @@
     # 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 "
+    is_clang = invoker.is_clang
+    if (is_clang) {
+      prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
+                           root_build_dir)
+      cc = "$prefix/clang"
+      cxx = "$prefix/clang++"
     } else {
-      compiler_prefix = ""
+      cc = "${tool_prefix}gcc"
+      cxx = "${tool_prefix}g++"
     }
-
-    cc = compiler_prefix + tool_prefix + "gcc"
-    cxx = compiler_prefix + tool_prefix + "g++"
     ar = tool_prefix + "ar"
     ld = cxx
-    readelf = compiler_prefix + tool_prefix + "readelf"
-    nm = compiler_prefix + tool_prefix + "nm"
+    readelf = tool_prefix + "readelf"
+    nm = tool_prefix + "nm"
+    strip = "${tool_prefix}strip"
 
     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") {
+template("android_gcc_toolchains_helper") {
+  android_gcc_toolchain(target_name) {
+    android_ndk_sysroot = invoker.android_ndk_sysroot
+    android_ndk_lib_dir = invoker.android_ndk_lib_dir
+    tool_prefix = invoker.tool_prefix
+    toolchain_cpu = invoker.toolchain_cpu
+  }
+
+  android_gcc_toolchain("clang_$target_name") {
+    android_ndk_sysroot = invoker.android_ndk_sysroot
+    android_ndk_lib_dir = invoker.android_ndk_lib_dir
+    tool_prefix = invoker.tool_prefix
+    toolchain_cpu = invoker.toolchain_cpu
+    is_clang = true
+  }
+}
+
+android_gcc_toolchains_helper("x86") {
   android_ndk_sysroot = "$android_ndk_root/$x86_android_sysroot_subdir"
   android_ndk_lib_dir = "usr/lib"
 
@@ -90,7 +79,7 @@
   toolchain_cpu = "x86"
 }
 
-android_gcc_toolchain("arm") {
+android_gcc_toolchains_helper("arm") {
   android_ndk_sysroot = "$android_ndk_root/$arm_android_sysroot_subdir"
   android_ndk_lib_dir = "usr/lib"
 
@@ -98,7 +87,7 @@
   toolchain_cpu = "arm"
 }
 
-android_gcc_toolchain("mipsel") {
+android_gcc_toolchains_helper("mipsel") {
   android_ndk_sysroot = "$android_ndk_root/$mips_android_sysroot_subdir"
   android_ndk_lib_dir = "usr/lib"
 
@@ -106,7 +95,7 @@
   toolchain_cpu = "mipsel"
 }
 
-android_gcc_toolchain("x64") {
+android_gcc_toolchains_helper("x64") {
   android_ndk_sysroot = "$android_ndk_root/$x86_64_android_sysroot_subdir"
   android_ndk_lib_dir = "usr/lib64"
 
@@ -114,7 +103,7 @@
   toolchain_cpu = "x86_64"
 }
 
-android_gcc_toolchain("arm64") {
+android_gcc_toolchains_helper("arm64") {
   android_ndk_sysroot = "$android_ndk_root/$arm64_android_sysroot_subdir"
   android_ndk_lib_dir = "usr/lib"
 
@@ -122,7 +111,7 @@
   toolchain_cpu = "aarch64"
 }
 
-android_gcc_toolchain("mips64el") {
+android_gcc_toolchains_helper("mips64el") {
   android_ndk_sysroot = "$android_ndk_root/$mips64_android_sysroot_subdir"
   android_ndk_lib_dir = "usr/lib64"
 
diff --git a/build/toolchain/clang.gni b/build/toolchain/clang.gni
deleted file mode 100644
index c680384..0000000
--- a/build/toolchain/clang.gni
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2013 The Chromium 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
index 140958b..5db3c20 100644
--- a/build/toolchain/cros/BUILD.gn
+++ b/build/toolchain/cros/BUILD.gn
@@ -2,7 +2,6 @@
 # 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() {
@@ -32,4 +31,6 @@
   toolchain_cpu = "${target_cpu}"
   toolchain_os = "linux"
   is_clang = is_clang
+  use_ccache = false
+  use_goma = false
 }
diff --git a/build/toolchain/gcc_ar_wrapper.py b/build/toolchain/gcc_ar_wrapper.py
new file mode 100755
index 0000000..a8f3190
--- /dev/null
+++ b/build/toolchain/gcc_ar_wrapper.py
@@ -0,0 +1,71 @@
+#!/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.
+
+"""Runs the 'ar' command after removing its output file first.
+
+This script is invoked like:
+  python gcc_ar_wrapper.py --ar=$AR --output=$OUT $OP $INPUTS
+to do the equivalent of:
+  rm -f $OUT && $AR $OP $OUT $INPUTS
+"""
+
+import argparse
+import os
+import subprocess
+import sys
+
+
+# When running on a Windows host and using a toolchain whose tools are
+# actually wrapper scripts (i.e. .bat files on Windows) rather than binary
+# executables, the "command" to run has to be prefixed with this magic.
+# The GN toolchain definitions take care of that for when GN/Ninja is
+# running the tool directly.  When that command is passed in to this
+# script, it appears as a unitary string but needs to be split up so that
+# just 'cmd' is the actual command given to Python's subprocess module.
+BAT_PREFIX = 'cmd /c call '
+
+def CommandToRun(command):
+  if command[0].startswith(BAT_PREFIX):
+    command = command[0].split(None, 3) + command[1:]
+  return command
+
+
+def main():
+  parser = argparse.ArgumentParser(description=__doc__)
+  parser.add_argument('--ar',
+                      required=True,
+                      help='The ar binary to run',
+                      metavar='PATH')
+  parser.add_argument('--output',
+                      required=True,
+                      help='Output archive file',
+                      metavar='ARCHIVE')
+  parser.add_argument('--plugin',
+                      help='Load plugin')
+  parser.add_argument('operation',
+                      help='Operation on the archive')
+  parser.add_argument('inputs', nargs='+',
+                      help='Input files')
+  args = parser.parse_args()
+
+  command = [args.ar, args.operation]
+  if args.plugin is not None:
+    command += ['--plugin', args.plugin]
+  command.append(args.output)
+  command += args.inputs
+
+  # Remove the output file first.
+  try:
+    os.remove(args.output)
+  except OSError as e:
+    if e.errno != os.errno.ENOENT:
+      raise
+
+  # Now just run the ar command.
+  return subprocess.call(CommandToRun(command))
+
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/build/toolchain/gcc_link_wrapper.py b/build/toolchain/gcc_link_wrapper.py
new file mode 100755
index 0000000..c701c1b
--- /dev/null
+++ b/build/toolchain/gcc_link_wrapper.py
@@ -0,0 +1,65 @@
+#!/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.
+
+"""Runs a linking command and optionally a strip command.
+
+This script exists to avoid using complex shell commands in
+gcc_toolchain.gni's tool("link"), in case the host running the compiler
+does not have a POSIX-like shell (e.g. Windows).
+"""
+
+import argparse
+import subprocess
+import sys
+
+
+# When running on a Windows host and using a toolchain whose tools are
+# actually wrapper scripts (i.e. .bat files on Windows) rather than binary
+# executables, the "command" to run has to be prefixed with this magic.
+# The GN toolchain definitions take care of that for when GN/Ninja is
+# running the tool directly.  When that command is passed in to this
+# script, it appears as a unitary string but needs to be split up so that
+# just 'cmd' is the actual command given to Python's subprocess module.
+BAT_PREFIX = 'cmd /c call '
+
+def CommandToRun(command):
+  if command[0].startswith(BAT_PREFIX):
+    command = command[0].split(None, 3) + command[1:]
+  return command
+
+
+def main():
+  parser = argparse.ArgumentParser(description=__doc__)
+  parser.add_argument('--strip',
+                      help='The strip binary to run',
+                      metavar='PATH')
+  parser.add_argument('--unstripped-file',
+                      required=True,
+                      help='Executable file produced by linking command',
+                      metavar='FILE')
+  parser.add_argument('--output',
+                      required=True,
+                      help='Final output executable file',
+                      metavar='FILE')
+  parser.add_argument('command', nargs='+',
+                      help='Linking command')
+  args = parser.parse_args()
+
+  # First, run the actual link.
+  result = subprocess.call(CommandToRun(args.command))
+  if result != 0:
+    return result
+
+  # Finally, strip the linked executable (if desired).
+  if args.strip:
+    result = subprocess.call(CommandToRun([
+        args.strip, '--strip-unneeded', '-o', args.output, args.unstripped_file
+        ]))
+
+  return result
+
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/build/toolchain/gcc_solink_wrapper.py b/build/toolchain/gcc_solink_wrapper.py
new file mode 100755
index 0000000..45c489d
--- /dev/null
+++ b/build/toolchain/gcc_solink_wrapper.py
@@ -0,0 +1,126 @@
+#!/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.
+
+"""Runs 'ld -shared' and generates a .TOC file that's untouched when unchanged.
+
+This script exists to avoid using complex shell commands in
+gcc_toolchain.gni's tool("solink"), in case the host running the compiler
+does not have a POSIX-like shell (e.g. Windows).
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+
+# When running on a Windows host and using a toolchain whose tools are
+# actually wrapper scripts (i.e. .bat files on Windows) rather than binary
+# executables, the "command" to run has to be prefixed with this magic.
+# The GN toolchain definitions take care of that for when GN/Ninja is
+# running the tool directly.  When that command is passed in to this
+# script, it appears as a unitary string but needs to be split up so that
+# just 'cmd' is the actual command given to Python's subprocess module.
+BAT_PREFIX = 'cmd /c call '
+
+def CommandToRun(command):
+  if command[0].startswith(BAT_PREFIX):
+    command = command[0].split(None, 3) + command[1:]
+  return command
+
+
+def CollectSONAME(args):
+  """Replaces: readelf -d $sofile | grep SONAME"""
+  toc = ''
+  readelf = subprocess.Popen(CommandToRun([args.readelf, '-d', args.sofile]),
+                             stdout=subprocess.PIPE, bufsize=-1)
+  for line in readelf.stdout:
+    if 'SONAME' in line:
+      toc += line
+  return readelf.wait(), toc
+
+
+def CollectDynSym(args):
+  """Replaces: nm --format=posix -g -D $sofile | cut -f1-2 -d' '"""
+  toc = ''
+  nm = subprocess.Popen(CommandToRun([
+      args.nm, '--format=posix', '-g', '-D', args.sofile]),
+                        stdout=subprocess.PIPE, bufsize=-1)
+  for line in nm.stdout:
+    toc += ' '.join(line.split(' ', 2)[:2]) + '\n'
+  return nm.wait(), toc
+
+
+def CollectTOC(args):
+  result, toc = CollectSONAME(args)
+  if result == 0:
+    result, dynsym = CollectDynSym(args)
+    toc += dynsym
+  return result, toc
+
+
+def UpdateTOC(tocfile, toc):
+  if os.path.exists(tocfile):
+    old_toc = open(tocfile, 'r').read()
+  else:
+    old_toc = None
+  if toc != old_toc:
+    open(tocfile, 'w').write(toc)
+
+
+def main():
+  parser = argparse.ArgumentParser(description=__doc__)
+  parser.add_argument('--readelf',
+                      required=True,
+                      help='The readelf binary to run',
+                      metavar='PATH')
+  parser.add_argument('--nm',
+                      required=True,
+                      help='The nm binary to run',
+                      metavar='PATH')
+  parser.add_argument('--strip',
+                      help='The strip binary to run',
+                      metavar='PATH')
+  parser.add_argument('--sofile',
+                      required=True,
+                      help='Shared object file produced by linking command',
+                      metavar='FILE')
+  parser.add_argument('--tocfile',
+                      required=True,
+                      help='Output table-of-contents file',
+                      metavar='FILE')
+  parser.add_argument('--output',
+                      required=True,
+                      help='Final output shared object file',
+                      metavar='FILE')
+  parser.add_argument('command', nargs='+',
+                      help='Linking command')
+  args = parser.parse_args()
+
+  # First, run the actual link.
+  result = subprocess.call(CommandToRun(args.command))
+  if result != 0:
+    return result
+
+  # Next, generate the contents of the TOC file.
+  result, toc = CollectTOC(args)
+  if result != 0:
+    return result
+
+  # If there is an existing TOC file with identical contents, leave it alone.
+  # Otherwise, write out the TOC file.
+  UpdateTOC(args.tocfile, toc)
+
+  # Finally, strip the linked shared object file (if desired).
+  if args.strip:
+    result = subprocess.call(CommandToRun([args.strip, '--strip-unneeded',
+                                           '-o', args.output, args.sofile]))
+
+  return result
+
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni
index ae9599a..ec138b1 100644
--- a/build/toolchain/gcc_toolchain.gni
+++ b/build/toolchain/gcc_toolchain.gni
@@ -2,6 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/nacl/config.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+import("//build/toolchain/ccache.gni")
+import("//build/toolchain/goma.gni")
+import("//build/toolchain/toolchain.gni")
+
 # This value will be inherited in the toolchain below.
 concurrent_links = exec_script("get_concurrent_links.py", [], "value")
 
@@ -13,15 +19,14 @@
 #  - cxx
 #  - ar
 #  - ld
-#  - readelf
-#  - nm
 # 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:
+# Optional parameters that control the tools:
+#
 #  - libs_section_prefix
 #  - libs_section_postfix
 #      The contents of these strings, if specified, will be placed around
@@ -30,35 +35,115 @@
 #  - 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.
+#  - link_outputs
+#      The content of this array, if specified, will be added to the list of
+#      outputs from the link command. This can be useful in conjunction with
+#      the post_link parameter.
+#  - post_link
+#      The content of this string, if specified, will be run as a separate
+#      command following the the link command.
 #  - deps
 #      Just forwarded to the toolchain definition.
+#  - executable_extension
+#      If this string is specified it will be used for the file extension
+#      for an executable, rather than using no extension; targets will
+#      still be able to override the extension using the output_extension
+#      variable.
+#  - rebuild_define
+#      The contents of this string, if specified, will be passed as a #define
+#      to the toolchain. It can be used to force recompiles whenever a
+#      toolchain is updated.
+#  - shlib_extension
+#      If this string is specified it will be used for the file extension
+#      for a shared library, rather than default value specified in
+#      toolchain.gni
+#  - strip
+#      Location of the strip executable. When specified, strip will be run on
+#      all shared libraries and executables as they are built. The pre-stripped
+#      artifacts will be put in lib.unstripped/ and exe.unstripped/.
+#
+# Optional build argument contols.
+#
+#  - clear_sanitizers
+#      When set to true, is_asan, is_msan, etc.will all be set to false. Often
+#      secondary toolchains do not want to run with sanitizers.
 #  - is_clang
+#      Whether to use clang instead of gcc.
+#  - is_component_build
+#      Whether to forcibly enable or disable component builds for this
+#      toolchain; if not specified, the toolchain will inherit the
+#      default setting.
+#  - is_nacl_glibc
+#      Whether NaCl code is built using Glibc instead of Newlib.
+#  - use_ccache
+#      Override the global use_ccache setting, useful to opt-out of ccache in
+#      a particular toolchain by setting use_ccache = false in it.
+#  - use_goma
+#      Override the global use_goma setting, useful to opt-out of goma in a
+#      particular toolchain by setting use_gome = false in it.
+#  - use_gold
+#      Override the global use_gold setting, useful if the particular
+#      toolchain has a custom link step that is not actually using Gold.
 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.readelf),
-           "gcc_toolchain() must specify a \"readelf\" value")
-    assert(defined(invoker.nm), "gcc_toolchain() must specify a \"nm\" 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
+    if (defined(invoker.use_ccache)) {
+      use_ccache = invoker.use_ccache
+    }
+    if (defined(invoker.use_goma)) {
+      use_goma = invoker.use_goma
+    }
+    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 = ""
+    }
+
+    # This define changes when the toolchain changes, forcing a rebuild.
+    # Nothing should ever use this define.
+    if (defined(invoker.rebuild_define)) {
+      rebuild_string = "-D" + invoker.rebuild_define + " "
+    } else {
+      rebuild_string = ""
+    }
+
+    cc = compiler_prefix + invoker.cc
+    cxx = compiler_prefix + invoker.cxx
     ar = invoker.ar
     ld = invoker.ld
-    readelf = invoker.readelf
-    nm = invoker.nm
+    if (defined(invoker.readelf)) {
+      readelf = invoker.readelf
+    } else {
+      readelf = "readelf"
+    }
+    if (defined(invoker.nm)) {
+      nm = invoker.nm
+    } else {
+      nm = "nm"
+    }
+
+    if (defined(invoker.shlib_extension)) {
+      default_shlib_extension = invoker.shlib_extension
+    } else {
+      default_shlib_extension = shlib_extension
+    }
+
+    if (defined(invoker.executable_extension)) {
+      default_executable_extension = invoker.executable_extension
+    } else {
+      default_executable_extension = ""
+    }
 
     # Bring these into our scope for string interpolation with default values.
     if (defined(invoker.libs_section_prefix)) {
@@ -89,40 +174,56 @@
     lib_switch = "-l"
     lib_dir_switch = "-L"
 
+    # Object files go in this directory.
+    object_subdir = "{{target_out_dir}}/{{label_name}}"
+
     tool("cc") {
       depfile = "{{output}}.d"
-      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+      command = "$cc -MMD -MF $depfile ${rebuild_string}{{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",
+        "$object_subdir/{{source_name_part}}.o",
       ]
     }
 
     tool("cxx") {
       depfile = "{{output}}.d"
-      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+      command = "$cxx -MMD -MF $depfile ${rebuild_string}{{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",
+        "$object_subdir/{{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}}"
+      command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
       depsformat = "gcc"
       description = "ASM {{output}}"
       outputs = [
-        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+        "$object_subdir/{{source_name_part}}.o",
       ]
     }
 
     tool("alink") {
       rspfile = "{{output}}.rsp"
-      command = "rm -f {{output}} && $ar rcs {{output}} @$rspfile"
+      arflags = ""
+      if (is_cfi && invoker.toolchain_os != "nacl") {
+        gold_plugin_path = rebase_path(
+                "//third_party/llvm-build/Release+Asserts/lib/LLVMgold.so",
+                root_build_dir)
+        arflags = "--plugin \"$gold_plugin_path\""
+      }
+
+      # This needs a Python script to avoid using simple sh features in this
+      # command, in case the host does not use a POSIX shell (e.g. compiling
+      # POSIX-like toolchains such as NaCl on Windows).
+      ar_wrapper =
+          rebase_path("//build/toolchain/gcc_ar_wrapper.py", root_build_dir)
+      command = "$python_path \"$ar_wrapper\" --output={{output}} --ar=\"$ar\" $arflags rcs @\"$rspfile\""
       description = "AR {{output}}"
       rspfile_content = "{{inputs}}"
       outputs = [
@@ -135,23 +236,37 @@
     tool("solink") {
       soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
       sofile = "{{root_out_dir}}/$soname"  # Possibly including toolchain dir.
+      if (shlib_subdir != ".") {
+        sofile = "{{root_out_dir}}/$shlib_subdir/$soname"
+      }
       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
+      unstripped_sofile = sofile
+      if (defined(invoker.strip)) {
+        unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname"
       }
+
+      # 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 (3) if the extracted list differs from the existing
+      # .TOC file, overwrite it, otherwise, don't change it.
+      tocfile = sofile + ".TOC"
+
+      link_command = "$ld -shared {{ldflags}} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\""
+
+      assert(defined(readelf), "to solink you must have a readelf")
+      assert(defined(nm), "to solink you must have an nm")
+      strip_switch = ""
+      if (defined(invoker.strip)) {
+        strip_switch = "--strip=${invoker.strip}"
+      }
+
+      # This needs a Python script to avoid using a complex shell command
+      # requiring sh control structures, pipelines, and POSIX utilities.
+      # The host might not have a POSIX shell and utilities (e.g. Windows).
+      solink_wrapper = rebase_path("//build/toolchain/gcc_solink_wrapper.py")
+      command = "$python_path \"$solink_wrapper\" --readelf=\"$readelf\" --nm=\"$nm\" $strip_switch --sofile=\"$unstripped_sofile\" --tocfile=\"$tocfile\" --output=\"$sofile\" -- $link_command"
+
       rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix"
 
       description = "SOLINK $sofile"
@@ -159,7 +274,7 @@
       # 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"
+      default_output_extension = default_shlib_extension
 
       output_prefix = "lib"
 
@@ -174,38 +289,95 @@
         sofile,
         tocfile,
       ]
-      if (defined(invoker.solink_outputs)) {
-        outputs += invoker.solink_outputs
+      if (sofile != unstripped_sofile) {
+        outputs += [ unstripped_sofile ]
       }
       link_output = sofile
       depend_output = tocfile
     }
 
+    tool("solink_module") {
+      soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
+      sofile = "{{root_out_dir}}/$soname"  # Possibly including toolchain dir.
+      if (shlib_subdir != ".") {
+        sofile = "{{root_out_dir}}/$shlib_subdir/$soname"
+      }
+      rspfile = sofile + ".rsp"
+
+      unstripped_sofile = sofile
+      if (defined(invoker.strip)) {
+        unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname"
+      }
+
+      command = "$ld -shared {{ldflags}} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\""
+
+      if (defined(invoker.strip)) {
+        strip_command = "${invoker.strip} --strip-unneeded -o \"$sofile\" \"$unstripped_sofile\""
+        command += " && " + strip_command
+      }
+      rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix"
+
+      description = "SOLINK_MODULE $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 = default_shlib_extension
+
+      output_prefix = "lib"
+
+      outputs = [
+        sofile,
+      ]
+      if (sofile != unstripped_sofile) {
+        outputs += [ unstripped_sofile ]
+      }
+    }
+
     tool("link") {
-      outfile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
+      exename = "{{target_output_name}}{{output_extension}}"
+      outfile = "{{root_out_dir}}/$exename"
       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
+      unstripped_outfile = outfile
+
+      # 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 = default_executable_extension
+
+      if (defined(invoker.strip)) {
+        unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$exename"
+      }
+
+      command = "$ld {{ldflags}} -o \"$unstripped_outfile\" -Wl,--start-group @\"$rspfile\" {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix"
+      if (defined(invoker.strip)) {
+        link_wrapper =
+            rebase_path("//build/toolchain/gcc_link_wrapper.py", root_build_dir)
+        command = "$python_path \"$link_wrapper\" --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\" --output=\"$outfile\" -- $command"
       }
       description = "LINK $outfile"
       rspfile_content = "{{inputs}}"
       outputs = [
         outfile,
       ]
+      if (outfile != unstripped_outfile) {
+        outputs += [ unstripped_outfile ]
+      }
       if (defined(invoker.link_outputs)) {
         outputs += invoker.link_outputs
       }
     }
 
+    # These two are really entirely generic, but have to be repeated in
+    # each toolchain because GN doesn't allow a template to be used here.
+    # See //build/toolchain/toolchain.gni for details.
     tool("stamp") {
-      command = "touch {{output}}"
-      description = "STAMP {{output}}"
+      command = stamp_command
+      description = stamp_description
     }
-
     tool("copy") {
-      command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
-      description = "COPY {{source}} {{output}}"
+      command = copy_command
+      description = copy_description
     }
 
     # When invoking this toolchain not as the default one, these args will be
@@ -218,13 +390,66 @@
       target_os = target_os
       target_cpu = target_cpu
 
-      if (defined(invoker.is_clang)) {
-        is_clang = invoker.is_clang
+      forward_variables_from(invoker,
+                             [
+                               "is_clang",
+                               "is_component_build",
+                               "is_nacl_glibc",
+                               "use_gold",
+                               "symbol_level",
+                             ])
+
+      if (defined(invoker.clear_sanitizers) && invoker.clear_sanitizers) {
+        is_asan = false
+        is_cfi = false
+        is_lsan = false
+        is_msan = false
+        is_syzyasan = false
+        is_tsan = false
+        is_ubsan = false
+        is_ubsan_vptr = false
       }
     }
 
-    if (defined(invoker.deps)) {
-      deps = invoker.deps
-    }
+    forward_variables_from(invoker, [ "deps" ])
+  }
+}
+
+# This is a shorthand for gcc_toolchain instances based on the
+# Chromium-built version of Clang.  Only the toolchain_cpu and
+# toolchain_os variables need to be specified by the invoker, and
+# optionally toolprefix if it's a cross-compile case.  Note that for
+# a cross-compile case this toolchain requires a config to pass the
+# appropriate -target option, or else it will actually just be doing
+# a native compile.  The invoker can optionally override use_gold too.
+template("clang_toolchain") {
+  assert(defined(invoker.toolchain_cpu),
+         "clang_toolchain() must specify a \"toolchain_cpu\"")
+  assert(defined(invoker.toolchain_os),
+         "clang_toolchain() must specify a \"toolchain_os\"")
+  if (defined(invoker.toolprefix)) {
+    toolprefix = invoker.toolprefix
+  } else {
+    toolprefix = ""
+  }
+
+  gcc_toolchain(target_name) {
+    prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
+                         root_build_dir)
+    cc = "$prefix/clang"
+    cxx = "$prefix/clang++"
+    ld = cxx
+    is_clang = true
+
+    readelf = "${toolprefix}readelf"
+    ar = "${toolprefix}ar"
+    nm = "${toolprefix}nm"
+
+    forward_variables_from(invoker,
+                           [
+                             "toolchain_cpu",
+                             "toolchain_os",
+                             "use_gold",
+                           ])
   }
 }
diff --git a/build/toolchain/get_concurrent_links.py b/build/toolchain/get_concurrent_links.py
index 6a40101..f8c927b 100644
--- a/build/toolchain/get_concurrent_links.py
+++ b/build/toolchain/get_concurrent_links.py
@@ -35,7 +35,9 @@
     stat = MEMORYSTATUSEX(dwLength=ctypes.sizeof(MEMORYSTATUSEX))
     ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat))
 
-    mem_limit = max(1, stat.ullTotalPhys / (4 * (2 ** 30)))  # total / 4GB
+    # VS 2015 uses 20% more working set than VS 2013 and can consume all RAM
+    # on a 64 GB machine.
+    mem_limit = max(1, stat.ullTotalPhys / (5 * (2 ** 30)))  # total / 5GB
     hard_cap = max(1, int(os.getenv('GYP_LINK_CONCURRENCY_MAX', 2**32)))
     return min(mem_limit, hard_cap)
   elif sys.platform.startswith('linux'):
diff --git a/build/toolchain/linux/BUILD.gn b/build/toolchain/linux/BUILD.gn
index 15ad5bd..c26452f 100644
--- a/build/toolchain/linux/BUILD.gn
+++ b/build/toolchain/linux/BUILD.gn
@@ -3,57 +3,38 @@
 # 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 = ""
+clang_toolchain("clang_arm") {
+  toolchain_cpu = "arm"
+  toolchain_os = "linux"
+  toolprefix = "arm-linux-gnueabihf-"
 }
 
 gcc_toolchain("arm") {
-  cc = "${compiler_prefix}arm-linux-gnueabi-gcc"
-  cxx = "${compiler_prefix}arm-linux-gnueabi-g++"
+  toolprefix = "arm-linux-gnueabihf-"
 
-  ar = "arm-linux-gnueabi-ar"
+  cc = "${toolprefix}gcc"
+  cxx = "${toolprefix}g++"
+
+  ar = "${toolprefix}ar"
   ld = cxx
-  readelf = "arm-linux-gnueabi-readelf"
-  nm = "arm-linux-gnueabi-nm"
+  readelf = "${toolprefix}readelf"
+  nm = "${toolprefix}nm"
 
   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++"
-  readelf = "readelf"
-  nm = "nm"
-  ar = "ar"
-  ld = cxx
-
+clang_toolchain("clang_x86") {
   toolchain_cpu = "x86"
   toolchain_os = "linux"
-  is_clang = true
 }
 
 gcc_toolchain("x86") {
-  cc = "${compiler_prefix}gcc"
-  cxx = "$compiler_prefix}g++"
+  cc = "gcc"
+  cxx = "g++"
 
   readelf = "readelf"
   nm = "nm"
@@ -65,30 +46,14 @@
   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++"
-
-  readelf = "readelf"
-  nm = "nm"
-  ar = "ar"
-  ld = cxx
-
+clang_toolchain("clang_x64") {
   toolchain_cpu = "x64"
   toolchain_os = "linux"
-  is_clang = true
 }
 
 gcc_toolchain("x64") {
-  cc = "${compiler_prefix}gcc"
-  cxx = "${compiler_prefix}g++"
+  cc = "gcc"
+  cxx = "g++"
 
   readelf = "readelf"
   nm = "nm"
@@ -100,6 +65,11 @@
   is_clang = false
 }
 
+clang_toolchain("clang_mipsel") {
+  toolchain_cpu = "mipsel"
+  toolchain_os = "linux"
+}
+
 gcc_toolchain("mipsel") {
   cc = "mipsel-linux-gnu-gcc"
   cxx = "mipsel-linux-gnu-g++"
@@ -111,4 +81,6 @@
   toolchain_cpu = "mipsel"
   toolchain_os = "linux"
   is_clang = false
+  use_ccache = false
+  use_goma = false
 }
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn
index da4ca05..a64387f 100644
--- a/build/toolchain/mac/BUILD.gn
+++ b/build/toolchain/mac/BUILD.gn
@@ -7,11 +7,12 @@
 # Linux.
 
 import("../goma.gni")
+import("//build/config/ios/ios_sdk.gni")
 
 assert(host_os == "mac")
 
-import("//build/toolchain/clang.gni")
 import("//build/toolchain/goma.gni")
+import("//build/toolchain/toolchain.gni")
 
 if (use_goma) {
   goma_prefix = "$goma_dir/gomacc "
@@ -48,54 +49,63 @@
     lib_switch = "-l"
     lib_dir_switch = "-L"
 
+    # Object files go in this directory. Use label_name instead of
+    # target_output_name since labels will generally have no spaces and will be
+    # unique in the directory.
+    object_subdir = "{{target_out_dir}}/{{label_name}}"
+
     tool("cc") {
       depfile = "{{output}}.d"
+      precompiled_header_type = "gcc"
       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",
+        "$object_subdir/{{source_name_part}}.o",
       ]
     }
 
     tool("cxx") {
       depfile = "{{output}}.d"
+      precompiled_header_type = "gcc"
       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",
+        "$object_subdir/{{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}}"
+      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
       depsformat = "gcc"
       description = "ASM {{output}}"
       outputs = [
-        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+        "$object_subdir/{{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}}"
+      precompiled_header_type = "gcc"
+      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
       depsformat = "gcc"
       description = "OBJC {{output}}"
       outputs = [
-        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+        "$object_subdir/{{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}}"
+      precompiled_header_type = "gcc"
+      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}"
       depsformat = "gcc"
       description = "OBJCXX {{output}}"
       outputs = [
-        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+        "$object_subdir/{{source_name_part}}.o",
       ]
     }
 
@@ -113,10 +123,10 @@
       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.
+      # These variables are not built into GN but are helpers that implement
+      # (1) linking to produce a .dylib, (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.
       #
       # As a special case, if the library reexports symbols from other dynamic
       # libraries, we always update the .TOC and skip the temporary file and
@@ -124,12 +134,19 @@
       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; }"
+      does_reexport_command = "[ ! -e \"$dylib\" -o ! -e \"$tocname\" ] || otool -l \"$dylib\" | grep -q LC_REEXPORT_DYLIB"
 
-      command = "if $does_reexport_command ; then $link_command && $extract_toc_command > $tocname; else $link_command && $extract_toc_command > $temporary_tocname && $replace_command ; fi; fi"
+      link_command =
+          "$ld -shared {{ldflags}} -o \"$dylib\" -Wl,-filelist,\"$rspfile\""
+      if (is_component_build) {
+        link_command += " -Wl,-install_name,@rpath/{{target_output_name}}{{output_extension}}"
+      }
+      link_command += " {{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}}"
 
@@ -157,10 +174,45 @@
       depend_output = tocname
     }
 
+    tool("solink_module") {
+      sofile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"  # eg "./libfoo.so"
+      rspfile = sofile + ".rsp"
+
+      link_command =
+          "$ld -bundle {{ldflags}} -o \"$sofile\" -Wl,-filelist,\"$rspfile\""
+      if (is_component_build) {
+        link_command += " -Wl,-install_name,@rpath/{{target_output_name}}{{output_extension}}"
+      }
+      link_command += " {{solibs}} {{libs}}"
+      command = link_command
+
+      rspfile_content = "{{inputs_newline}}"
+
+      description = "SOLINK_MODULE {{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 = ".so"
+
+      outputs = [
+        sofile,
+      ]
+    }
+
     tool("link") {
       outfile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
       rspfile = "$outfile.rsp"
-      command = "$ld {{ldflags}} -o $outfile -Wl,-filelist,$rspfile {{solibs}} {{libs}}"
+
+      # Note about --filelist: Apple's linker reads the file list file and
+      # interprets each newline-separated chunk of text as a file name. It
+      # doesn't do the things one would expect from the shell like unescaping
+      # or handling quotes. In contrast, when Ninja finds a file name with
+      # spaces, it single-quotes them in $inputs_newline as it would normally
+      # do for command-line arguments. Thus any source names with spaces, or
+      # label names with spaces (which GN bases the output paths on) will be
+      # corrupted by this process. Don't use spaces for source files or labels.
+      command = "$ld {{ldflags}} -o \"$outfile\" -Wl,-filelist,\"$rspfile\" {{solibs}} {{libs}}"
       description = "LINK $outfile"
       rspfile_content = "{{inputs_newline}}"
       outputs = [
@@ -168,14 +220,16 @@
       ]
     }
 
+    # These two are really entirely generic, but have to be repeated in
+    # each toolchain because GN doesn't allow a template to be used here.
+    # See //build/toolchain/toolchain.gni for details.
     tool("stamp") {
-      command = "touch {{output}}"
-      description = "STAMP {{output}}"
+      command = stamp_command
+      description = stamp_description
     }
-
     tool("copy") {
-      command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
-      description = "COPY {{source}} {{output}}"
+      command = copy_command
+      description = copy_description
     }
 
     toolchain_args() {
@@ -204,6 +258,21 @@
   is_clang = true
 }
 
+mac_toolchain("ios_clang_arm") {
+  # TODO(GYP): Do we need ios_clang_armv7 and ios_clang_arm64 ?
+  toolchain_cpu = "arm"
+  toolchain_os = "mac"
+
+  # TODO(GYP): We need to support being able to use the version of clang
+  # shipped w/ XCode instead of the one pulled from upstream.
+  prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
+                       root_build_dir)
+  cc = "${goma_prefix}$prefix/clang"
+  cxx = "${goma_prefix}$prefix/clang++"
+  ld = cxx
+  is_clang = true
+}
+
 mac_toolchain("arm") {
   toolchain_cpu = "arm"
   toolchain_os = "mac"
diff --git a/build/toolchain/nacl/BUILD.gn b/build/toolchain/nacl/BUILD.gn
index 5fa637c..3896e19 100644
--- a/build/toolchain/nacl/BUILD.gn
+++ b/build/toolchain/nacl/BUILD.gn
@@ -1,63 +1,269 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright (c) 2014 The Native Client 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++"
+import("//build/config/sysroot.gni")
+import("//build/config/nacl/config.gni")
+import("//build/toolchain/nacl_toolchain.gni")
 
-  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"
+# Add the toolchain revision as a preprocessor define so that sources are
+# rebuilt when a toolchain is updated.
+# Idea we could use the toolchain deps feature, but currently that feature is
+# bugged and does not trigger a rebuild.
+# https://code.google.com/p/chromium/issues/detail?id=431880
+# Calls to get the toolchain revision are relatively slow, so do them all in a
+# single batch to amortize python startup, etc.
+revisions = exec_script("//native_client/build/get_toolchain_revision.py",
+                        [
+                          "nacl_x86_glibc",
+                          "nacl_arm_glibc",
+                          "pnacl_newlib",
+                        ],
+                        "trim list lines")
+nacl_x86_glibc_rev = revisions[0]
+nacl_arm_glibc_rev = revisions[1]
 
-    #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"
+# TODO(mcgrathr): Uncomment this when
+# https://code.google.com/p/chromium/issues/detail?id=395883 is fixed.
+#pnacl_newlib_rev = revisions[2]
 
-    #pool = "link_pool"
-  }
+template("pnacl_toolchain") {
+  assert(defined(invoker.executable_extension),
+         "Must define executable_extension")
 
-  if (is_win) {
-    tool("stamp") {
-      command = "$python_path gyp-win-tool stamp \$out"
-      description = "STAMP \$out"
-    }
+  # TODO(mcgrathr): See above.
+  pnacl_newlib_rev = revisions[2]
+
+  # The PNaCl toolchain tools are all wrapper scripts rather than binary
+  # executables.  On POSIX systems, nobody cares what kind of executable
+  # file you are.  But on Windows, scripts (.bat files) cannot be run
+  # directly and need the Windows shell (cmd.exe) specified explicily.
+  # TODO(mcgrathr): Hoist this to top level when
+  # https://code.google.com/p/chromium/issues/detail?id=395883 is fixed.
+  if (host_os == "win") {
+    # NOTE!  The //build/toolchain/gcc_*_wrapper.py scripts recognize
+    # this exact prefix string, so they must be updated if this string
+    # is changed in any way.
+    scriptprefix = "cmd /c call "
+    scriptsuffix = ".bat"
   } else {
-    tool("stamp") {
-      command = "touch \$out"
-      description = "STAMP \$out"
+    scriptprefix = ""
+    scriptsuffix = ""
+  }
+
+  # When the compilers are run via goma or ccache rather than directly by
+  # GN/Ninja, the goma/ccache wrapper handles .bat files but gets confused
+  # by being given the scriptprefix.
+  if (host_os == "win" && !use_goma && !use_ccache) {
+    compiler_scriptprefix = scriptprefix
+  } else {
+    compiler_scriptprefix = ""
+  }
+
+  nacl_toolchain(target_name) {
+    toolchain_package = "pnacl_newlib"
+    toolchain_revision = pnacl_newlib_rev
+    toolchain_cpu = "pnacl"
+    toolprefix =
+        rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/pnacl-",
+                    root_build_dir)
+
+    is_clang = true
+    cc = compiler_scriptprefix + toolprefix + "clang" + scriptsuffix
+    cxx = compiler_scriptprefix + toolprefix + "clang++" + scriptsuffix
+    ar = scriptprefix + toolprefix + "ar" + scriptsuffix
+    readelf = scriptprefix + toolprefix + "readelf" + scriptsuffix
+    nm = scriptprefix + toolprefix + "nm" + scriptsuffix
+    if (defined(invoker.strip)) {
+      strip = scriptprefix + toolprefix + invoker.strip + scriptsuffix
     }
+
+    # Note this is not the usual "ld = cxx" because "ld" uses are
+    # never run via goma, so this needs scriptprefix.
+    ld = scriptprefix + toolprefix + "clang++" + scriptsuffix
+
+    executable_extension = invoker.executable_extension
+  }
+}
+
+pnacl_toolchain("newlib_pnacl") {
+  executable_extension = ".pexe"
+
+  # The pnacl-finalize tool turns a .pexe.debug file into a .pexe file.
+  # It's very similar in purpose to the traditional "strip" utility: it
+  # turns what comes out of the linker into what you actually want to
+  # distribute and run.  PNaCl doesn't have a "strip"-like utility that
+  # you ever actually want to use other than pnacl-finalize, so just
+  # make pnacl-finalize the strip tool rather than adding an additional
+  # step like "postlink" to run pnacl-finalize.
+  strip = "finalize"
+}
+
+pnacl_toolchain("newlib_pnacl_nonsfi") {
+  executable_extension = ""
+  strip = "strip"
+}
+
+template("nacl_glibc_toolchain") {
+  toolchain_cpu = target_name
+  assert(defined(invoker.toolchain_tuple), "Must define toolchain_tuple")
+  assert(defined(invoker.toolchain_package), "Must define toolchain_package")
+  assert(defined(invoker.toolchain_revision), "Must define toolchain_revision")
+  forward_variables_from(invoker,
+                         [
+                           "toolchain_package",
+                           "toolchain_revision",
+                         ])
+
+  toolprefix = rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/" +
+                               invoker.toolchain_tuple + "-",
+                           root_build_dir)
+
+  # TODO(mcgrathr): Hoist this to top level when
+  # https://code.google.com/p/chromium/issues/detail?id=395883 is fixed.
+  if (host_os == "win") {
+    toolsuffix = ".exe"
+  } else {
+    toolsuffix = ""
   }
 
-  toolchain_args() {
-    # Override the default OS detection. The build config will set the is_*
-    # flags accordingly.
-    current_os = "nacl"
+  nacl_toolchain("glibc_" + toolchain_cpu) {
+    is_clang = false
+    is_nacl_glibc = true
 
-    # Component build not supported in NaCl, since it does not support shared
-    # libraries.
-    is_component_build = false
+    cc = toolprefix + "gcc" + toolsuffix
+    cxx = toolprefix + "g++" + toolsuffix
+    ar = toolprefix + "ar" + toolsuffix
+    ld = cxx
+    readelf = toolprefix + "readelf" + toolsuffix
+    nm = toolprefix + "nm" + toolsuffix
+    strip = toolprefix + "strip" + toolsuffix
   }
 }
+
+nacl_glibc_toolchain("x86") {
+  toolchain_package = "nacl_x86_glibc"
+  toolchain_revision = nacl_x86_glibc_rev
+  toolchain_tuple = "i686-nacl"
+}
+
+nacl_glibc_toolchain("x64") {
+  toolchain_package = "nacl_x86_glibc"
+  toolchain_revision = nacl_x86_glibc_rev
+  toolchain_tuple = "x86_64-nacl"
+}
+
+nacl_glibc_toolchain("arm") {
+  toolchain_package = "nacl_arm_glibc"
+  toolchain_revision = nacl_arm_glibc_rev
+  toolchain_tuple = "arm-nacl"
+}
+
+template("nacl_clang_toolchain") {
+  toolchain_cpu = target_name
+  assert(defined(invoker.toolchain_tuple), "Must define toolchain_tuple")
+
+  # TODO(mcgrathr): See above.
+  pnacl_newlib_rev = revisions[2]
+
+  toolchain_package = "pnacl_newlib"
+  toolchain_revision = pnacl_newlib_rev
+  toolprefix = rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/" +
+                               invoker.toolchain_tuple + "-",
+                           root_build_dir)
+
+  # TODO(mcgrathr): Hoist this to top level when
+  # https://code.google.com/p/chromium/issues/detail?id=395883 is fixed.
+  if (host_os == "win") {
+    toolsuffix = ".exe"
+  } else {
+    toolsuffix = ""
+  }
+
+  nacl_toolchain("clang_newlib_" + toolchain_cpu) {
+    is_clang = true
+    cc = toolprefix + "clang" + toolsuffix
+    cxx = toolprefix + "clang++" + toolsuffix
+    ar = toolprefix + "ar" + toolsuffix
+    ld = cxx
+    readelf = toolprefix + "readelf" + toolsuffix
+    nm = toolprefix + "nm" + toolsuffix
+    strip = toolprefix + "strip" + toolsuffix
+  }
+}
+
+template("nacl_irt_toolchain") {
+  toolchain_cpu = target_name
+  assert(defined(invoker.toolchain_tuple), "Must define toolchain_tuple")
+
+  # TODO(mcgrathr): See above.
+  pnacl_newlib_rev = revisions[2]
+
+  toolchain_package = "pnacl_newlib"
+  toolchain_revision = pnacl_newlib_rev
+  toolprefix = rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/" +
+                               invoker.toolchain_tuple + "-",
+                           root_build_dir)
+
+  # TODO(mcgrathr): Hoist this to top level when
+  # https://code.google.com/p/chromium/issues/detail?id=395883 is fixed.
+  if (host_os == "win") {
+    toolsuffix = ".exe"
+  } else {
+    toolsuffix = ""
+  }
+
+  link_irt = rebase_path("//native_client/build/link_irt.py", root_build_dir)
+
+  tls_edit_label =
+      "//native_client/src/tools/tls_edit:tls_edit($host_toolchain)"
+  host_toolchain_out_dir =
+      rebase_path(get_label_info(tls_edit_label, "root_out_dir"),
+                  root_build_dir)
+  tls_edit = "${host_toolchain_out_dir}/tls_edit"
+
+  nacl_toolchain("irt_" + toolchain_cpu) {
+    is_clang = true
+    cc = toolprefix + "clang" + toolsuffix
+    cxx = toolprefix + "clang++" + toolsuffix
+    ar = toolprefix + "ar" + toolsuffix
+    readelf = toolprefix + "readelf" + toolsuffix
+    nm = toolprefix + "nm" + toolsuffix
+    strip = toolprefix + "strip" + toolsuffix
+
+    # Always build the IRT with full debugging symbols, regardless of
+    # how Chromium itself is being built (or other NaCl executables).
+    symbol_level = 2
+
+    # Some IRT implementations (notably, Chromium's) contain C++ code,
+    # so we need to link w/ the C++ linker.
+    ld = "${python_path} ${link_irt} --tls-edit=${tls_edit} --link-cmd=${cxx} --readelf-cmd=${readelf}"
+
+    # TODO(ncbray): depend on link script
+    deps = [
+      tls_edit_label,
+    ]
+  }
+}
+
+template("nacl_clang_toolchains") {
+  assert(defined(invoker.toolchain_tuple), "Must define toolchain_tuple")
+  nacl_clang_toolchain(target_name) {
+    toolchain_tuple = invoker.toolchain_tuple
+  }
+  nacl_irt_toolchain(target_name) {
+    toolchain_tuple = invoker.toolchain_tuple
+  }
+}
+
+nacl_clang_toolchains("x86") {
+  toolchain_tuple = "i686-nacl"
+}
+
+nacl_clang_toolchains("x64") {
+  toolchain_tuple = "x86_64-nacl"
+}
+
+nacl_clang_toolchains("arm") {
+  toolchain_tuple = "arm-nacl"
+}
diff --git a/build/toolchain/nacl_toolchain.gni b/build/toolchain/nacl_toolchain.gni
new file mode 100644
index 0000000..0e19411
--- /dev/null
+++ b/build/toolchain/nacl_toolchain.gni
@@ -0,0 +1,58 @@
+# Copyright (c) 2014 The Native Client 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/nacl/config.gni")
+import("//build/toolchain/gcc_toolchain.gni")
+
+# This template defines a NaCl toolchain.
+#
+# 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.)
+
+template("nacl_toolchain") {
+  assert(defined(invoker.cc), "nacl_toolchain() must specify a \"cc\" value")
+  assert(defined(invoker.cxx), "nacl_toolchain() must specify a \"cxx\" value")
+  assert(defined(invoker.ar), "nacl_toolchain() must specify a \"ar\" value")
+  assert(defined(invoker.ld), "nacl_toolchain() must specify a \"ld\" value")
+  assert(defined(invoker.toolchain_cpu),
+         "nacl_toolchain() must specify a \"toolchain_cpu\"")
+  gcc_toolchain(target_name) {
+    toolchain_os = "nacl"
+
+    if (defined(invoker.executable_extension)) {
+      executable_extension = invoker.executable_extension
+    } else {
+      executable_extension = ".nexe"
+    }
+
+    forward_variables_from(invoker,
+                           [
+                             "ar",
+                             "cc",
+                             "cxx",
+                             "deps",
+                             "is_clang",
+                             "is_nacl_glibc",
+                             "ld",
+                             "link_outputs",
+                             "nm",
+                             "readelf",
+                             "strip",
+                             "symbol_level",
+                             "toolchain_cpu",
+                           ])
+
+    # We do not support component builds or sanitizers with the NaCl toolchains.
+    is_component_build = false
+    clear_sanitizers = true
+
+    rebuild_define = "NACL_TC_REV=" + invoker.toolchain_revision
+  }
+}
diff --git a/build/toolchain/toolchain.gni b/build/toolchain/toolchain.gni
new file mode 100644
index 0000000..e7f4379
--- /dev/null
+++ b/build/toolchain/toolchain.gni
@@ -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.
+
+# Toolchain-related configuration that may be needed outside the context of the
+# toolchain() rules themselves.
+
+# Subdirectory within root_out_dir for shared library files.
+# TODO(agrieve): GYP sets this to "lib" for Linux & Android, but this won't work
+#     in GN until support for loadable_module() is added.
+#     See: https://codereview.chromium.org/1236503002/
+shlib_subdir = "."
+
+# Root out dir for shared library files.
+root_shlib_dir = root_out_dir
+if (shlib_subdir != ".") {
+  root_shlib_dir += "/$shlib_subdir"
+}
+
+# Extension for shared library files (including leading dot).
+if (is_mac || is_ios) {
+  shlib_extension = ".dylib"
+} else if (is_android && is_component_build) {
+  # By appending .cr, we prevent name collisions with libraries already
+  # loaded by the Android zygote.
+  shlib_extension = ".cr.so"
+} else if (is_posix) {
+  shlib_extension = ".so"
+} else if (is_win) {
+  shlib_extension = ".dll"
+} else {
+  assert(false, "Platform not supported")
+}
+
+# Prefix for shared library files.
+if (is_posix) {
+  shlib_prefix = "lib"
+} else {
+  shlib_prefix = ""
+}
+
+# While other "tool"s in a toolchain are specific to the target of that
+# toolchain, the "stamp" and "copy" tools are really generic to the host;
+# but each toolchain must define them separately.  GN doesn't allow a
+# template instantiation inside a toolchain definition, so some boilerplate
+# has to be repeated in each toolchain to define these two tools.  These
+# four variables reduce the duplication in that boilerplate.
+stamp_description = "STAMP {{output}}"
+copy_description = "COPY {{source}} {{output}}"
+if (host_os == "win") {
+  stamp_command = "$python_path gyp-win-tool stamp {{output}}"
+  copy_command =
+      "$python_path gyp-win-tool recursive-mirror {{source}} {{output}}"
+} else {
+  stamp_command = "touch {{output}}"
+  copy_command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
+}
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index 05406c3..777c6e9 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -2,17 +2,9 @@
 # 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")
+import("//build/toolchain/toolchain.gni")
 
 # Should only be running on Windows.
 assert(is_win)
@@ -25,25 +17,35 @@
 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
+if (use_goma) {
+  goma_prefix = "$goma_dir/gomacc.exe "
+} else {
+  goma_prefix = ""
 }
 
 # This value will be inherited in the toolchain below.
 concurrent_links = exec_script("../get_concurrent_links.py", [], "value")
 
+# Copy the VS runtime DLL for the default toolchain to the root build directory
+# so things will run.
+if (current_toolchain == default_toolchain) {
+  if (is_debug) {
+    configuration_name = "Debug"
+  } else {
+    configuration_name = "Release"
+  }
+  exec_script("../../vs_toolchain.py",
+              [
+                "copy_dlls",
+                rebase_path(root_build_dir),
+                configuration_name,
+                target_cpu,
+              ])
+}
+
 # Parameters:
 #  current_cpu: current_cpu to pass as a build arg
+#  current_os: current_os to pass as a build arg
 #  environment: File name of environment file.
 template("msvc_toolchain") {
   if (defined(invoker.concurrent_links)) {
@@ -52,54 +54,40 @@
 
   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\""
+  cl = invoker.cl
 
   toolchain(target_name) {
     # Make these apply to all tools below.
     lib_switch = ""
     lib_dir_switch = "/LIBPATH:"
 
+    # Object files go in this directory.
+    object_subdir = "{{target_out_dir}}/{{label_name}}"
+
     tool("cc") {
       rspfile = "{{output}}.rsp"
-      pdbname = "{{target_out_dir}}/{{target_output_name}}_c.pdb"
+      precompiled_header_type = "msvc"
+      pdbname = "{{target_out_dir}}/{{label_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",
+        "$object_subdir/{{source_name_part}}.obj",
       ]
       rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}"
     }
 
     tool("cxx") {
       rspfile = "{{output}}.rsp"
+      precompiled_header_type = "msvc"
 
       # The PDB name needs to be different between C and C++ compiled files.
-      pdbname = "{{target_out_dir}}/{{target_output_name}}_cc.pdb"
+      pdbname = "{{target_out_dir}}/{{label_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",
+        "$object_subdir/{{source_name_part}}.obj",
       ]
       rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}"
     }
@@ -107,18 +95,21 @@
     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",
+        "$object_subdir/{{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}}"
+      if (current_cpu == "x64") {
+        ml = "ml64.exe"
+      } else {
+        ml = "ml.exe"
+      }
+      command = "$python_path gyp-win-tool asm-wrapper $env $ml {{defines}} {{include_dirs}} {{asmflags}} /c /Fo{{output}} {{source}}"
       description = "ASM {{output}}"
       outputs = [
-        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
+        "$object_subdir/{{source_name_part}}.obj",
       ]
     }
 
@@ -140,8 +131,7 @@
 
     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
+      libname = "${dllname}.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"
@@ -160,6 +150,30 @@
       link_output = libname
       depend_output = libname
 
+      # Since the above commands only updates the .lib file when it changes, ask
+      # Ninja to check if the timestamp actually changed to know if downstream
+      # dependencies should be recompiled.
+      restat = true
+
+      # 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("solink_module") {
+      dllname = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"  # e.g. foo.dll
+      rspfile = "${dllname}.rsp"
+
+      link_command = "$python_path gyp-win-tool link-wrapper $env False link.exe /nologo /DLL /OUT:$dllname /PDB:${dllname}.pdb @$rspfile"
+
+      command = link_command
+
+      default_output_extension = ".dll"
+      description = "LINK_MODULE(DLL) {{output}}"
+      outputs = [
+        dllname,
+      ]
+
       # 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}}"
@@ -186,41 +200,112 @@
       rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
     }
 
+    # These two are really entirely generic, but have to be repeated in
+    # each toolchain because GN doesn't allow a template to be used here.
+    # See //build/toolchain/toolchain.gni for details.
     tool("stamp") {
-      command = "$python_path gyp-win-tool stamp {{output}}"
-      description = "STAMP {{output}}"
+      command = stamp_command
+      description = stamp_description
     }
-
     tool("copy") {
-      command =
-          "$python_path gyp-win-tool recursive-mirror {{source}} {{output}}"
-      description = "COPY {{source}} {{output}}"
+      command = copy_command
+      description = copy_description
     }
 
     # 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
+      if (defined(invoker.is_clang)) {
+        is_clang = invoker.is_clang
+      }
+      current_os = invoker.current_os
     }
   }
 }
 
-# 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"
+# 32-bit toolchains. Only define these when the target architecture is 32-bit
+# since we don't do any 32-bit cross compiles when targeting 64-bit (the
+# build does generate some 64-bit stuff from 32-bit target builds).
+if (target_cpu == "x86") {
+  x86_toolchain_data = exec_script("setup_toolchain.py",
+                                   [
+                                     visual_studio_path,
+                                     gyp_win_tool_path,
+                                     windows_sdk_path,
+                                     visual_studio_runtime_dirs,
+                                     "x86",
+                                   ],
+                                   "scope")
 
+  msvc_toolchain("x86") {
+    environment = "environment.x86"
     current_cpu = "x86"
+    cl = "${goma_prefix}\"${x86_toolchain_data.vc_bin_dir}/cl.exe\""
+    is_clang = false
+  }
+
+  msvc_toolchain("clang_x86") {
+    environment = "environment.x86"
+    current_cpu = "x86"
+    prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
+                         root_build_dir)
+    cl = "${goma_prefix}$prefix/clang-cl.exe"
+    current_os = "win"
+    is_clang = true
   }
 }
 
-if (current_cpu == "x64") {
-  msvc_toolchain("64") {
-    environment = "environment.x64"
+# 64-bit toolchains.
+x64_toolchain_data = exec_script("setup_toolchain.py",
+                                 [
+                                   visual_studio_path,
+                                   gyp_win_tool_path,
+                                   windows_sdk_path,
+                                   visual_studio_runtime_dirs,
+                                   "x64",
+                                 ],
+                                 "scope")
+
+msvc_toolchain("x64") {
+  environment = "environment.x64"
+  current_cpu = "x64"
+  cl = "${goma_prefix}\"${x64_toolchain_data.vc_bin_dir}/cl.exe\""
+  is_clang = false
+}
+
+msvc_toolchain("clang_x64") {
+  environment = "environment.x64"
+  current_cpu = "x64"
+  prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
+                       root_build_dir)
+  cl = "${goma_prefix}$prefix/clang-cl.exe"
+  current_os = "win"
+  is_clang = true
+}
+
+# WinRT toolchains. Only define these when targeting them.
+#
+# NOTE: This is currently broken because it references vc_bin_dir. brettw@
+# changed this around a bit, and I don't know what this should be set to
+# in terms of what setup_toolchain returns for a certain CPU architecture.
+if (target_os == "winrt_81" || target_os == "winrt_81_phone" ||
+    target_os == "winrt_10") {
+  msvc_toolchain("winrt_x86") {
+    environment = "environment.winrt_x86"
+    cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\""
+    is_clang = false
+
+    current_cpu = "x86"
+    current_os = current_os
+  }
+
+  msvc_toolchain("winrt_x64") {
+    environment = "environment.winrt_x64"
+    cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\""
+    is_clang = false
 
     current_cpu = "x64"
+    current_os = current_os
   }
 }
diff --git a/build/toolchain/win/midl.gni b/build/toolchain/win/midl.gni
index 748b0fc..ff5899c 100644
--- a/build/toolchain/win/midl.gni
+++ b/build/toolchain/win/midl.gni
@@ -6,7 +6,8 @@
 
 import("//build/config/win/visual_studio_version.gni")
 
-# This template defines a rule to invoke the MS IDL compiler.
+# This template defines a rule to invoke the MS IDL compiler. The generated
+# source code will be compiled and linked into targets that depend on this.
 #
 # Parameters
 #
@@ -84,22 +85,20 @@
       "/Oicf",
     ]
 
-    if (defined(invoker.deps)) {
-      deps = invoker.deps
-    }
+    forward_variables_from(invoker, [ "deps" ])
   }
 
   source_set(target_name) {
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
-    }
+    forward_variables_from(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 = [
+    public_deps = [
       ":$action_name",
     ]
+
+    configs += [ "//build/config/win:midl_warnings" ]
   }
 }
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
index bc9bd1e..f395044 100644
--- a/build/toolchain/win/setup_toolchain.py
+++ b/build/toolchain/win/setup_toolchain.py
@@ -146,6 +146,15 @@
     with open('environment.' + cpu, 'wb') as f:
       f.write(env_block)
 
+    # Create a store app version of the environment.
+    if 'LIB' in env:
+      env['LIB']     = env['LIB']    .replace(r'\VC\LIB', r'\VC\LIB\STORE')
+    if 'LIBPATH' in env:
+      env['LIBPATH'] = env['LIBPATH'].replace(r'\VC\LIB', r'\VC\LIB\STORE')
+    env_block = _FormatAsEnvironmentBlock(env)
+    with open('environment.winrt_' + cpu, 'wb') as f:
+        f.write(env_block)
+
   assert vc_bin_dir
   print 'vc_bin_dir = "%s"' % vc_bin_dir
 
diff --git a/build/toolchain_vs2013.hash b/build/toolchain_vs2013.hash
deleted file mode 100644
index 4ed8816..0000000
--- a/build/toolchain_vs2013.hash
+++ /dev/null
@@ -1 +0,0 @@
-ee7d718ec60c2dc5d255bbe325909c2021a7efef
diff --git a/build/uiautomator_test.gypi b/build/uiautomator_test.gypi
deleted file mode 100644
index e9bd0bf..0000000
--- a/build/uiautomator_test.gypi
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (c) 2013 The Chromium Authors. All 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
index 735733a..fa2d107 100755
--- a/build/update-linux-sandbox.sh
+++ b/build/update-linux-sandbox.sh
@@ -39,8 +39,9 @@
 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"
+  echo "Could not find ${CHROME_SANDBOX_BUILD_PATH}"
+  echo -n "BUILDTYPE is $BUILDTYPE, use \"BUILDTYPE=<value> ${0}\" to override "
+  echo "after you build the chrome_sandbox target"
   exit 1
 fi
 
diff --git a/build/util/BUILD.gn b/build/util/BUILD.gn
index c18f0ce..ad6f2ea 100644
--- a/build/util/BUILD.gn
+++ b/build/util/BUILD.gn
@@ -7,14 +7,13 @@
 
   lastchange_file = "LASTCHANGE.blink"
 
-  # TODO(brettw) move from content to this directory.
-  template_file = "//content/webkit_version.h.in"
+  template_file = "webkit_version.h.in"
   inputs = [
     lastchange_file,
     template_file,
   ]
 
-  output_file = "$root_gen_dir/webkit_version.h"
+  output_file = "$target_gen_dir/webkit_version.h"
   outputs = [
     output_file,
   ]
@@ -26,3 +25,23 @@
     rebase_path(output_file, root_build_dir),
   ]
 }
+
+action("chrome_version_json") {
+  script = "version.py"
+  _chrome_version_path = "//chrome/VERSION"
+  inputs = [
+    _chrome_version_path,
+  ]
+  _output_file = "$root_gen_dir/CHROME_VERSION.json"
+  outputs = [
+    _output_file,
+  ]
+  args = [
+    "--file",
+    rebase_path(_chrome_version_path, root_build_dir),
+    "--template",
+    "{\"full-quoted\": \"\\\"@MAJOR@.@MINOR@.@BUILD@.@PATCH@\\\"\"}",
+    "--output",
+    rebase_path(_output_file, root_build_dir),
+  ]
+}
diff --git a/build/util/java_action.gni b/build/util/java_action.gni
new file mode 100644
index 0000000..d9ca472
--- /dev/null
+++ b/build/util/java_action.gni
@@ -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.
+
+jarrunner = "//build/util/java_action.py"
+
+# Declare a target that runs a java command a single time.
+#
+# This target type allows you to run a java command a single time to produce
+# one or more output files. If you want to run a java command for each of a
+# set of input files, see "java_action_foreach".
+#
+# See "gn help action" for more information on how to use this target. This
+# template is based on the "action" and supports the same variables.
+template("java_action") {
+  assert(defined(invoker.script),
+         "Need script in $target_name listing the .jar file to run.")
+  assert(defined(invoker.outputs),
+         "Need outputs in $target_name listing the generated outputs.")
+
+  jarscript = invoker.script
+  action(target_name) {
+    script = jarrunner
+
+    inputs = [
+      jarscript,
+    ]
+    if (defined(invoker.inputs)) {
+      inputs += invoker.inputs
+    }
+
+    args = [
+      "-jar",
+      rebase_path(jarscript, root_build_dir),
+    ]
+    if (defined(invoker.args)) {
+      args += invoker.args
+    }
+
+    forward_variables_from(invoker,
+                           [
+                             "console",
+                             "data",
+                             "data_deps",
+                             "depfile",
+                             "deps",
+                             "outputs",
+                             "sources",
+                             "visibility",
+                           ])
+  }
+}
+
+# Declare a target that runs a java command over a set of files.
+#
+# This target type allows you to run a java command once-per-file over a set of
+# sources. If you want to run a java command once that takes many files as
+# input, see "java_action".
+#
+# See "gn help action_foreach" for more information on how to use this target.
+# This template is based on the "action_foreach" supports the same variables.
+template("java_action_foreach") {
+  assert(defined(invoker.script),
+         "Need script in $target_name listing the .jar file to run.")
+  assert(defined(invoker.outputs),
+         "Need outputs in $target_name listing the generated outputs.")
+  assert(defined(invoker.sources),
+         "Need sources in $target_name listing the target inputs.")
+
+  jarscript = invoker.script
+  action_foreach(target_name) {
+    script = jarrunner
+
+    inputs = [
+      jarscript,
+    ]
+    if (defined(invoker.inputs)) {
+      inputs += invoker.inputs
+    }
+
+    args = [
+      "-jar",
+      rebase_path(jarscript, root_build_dir),
+    ]
+    if (defined(invoker.args)) {
+      args += invoker.args
+    }
+
+    forward_variables_from(invoker,
+                           [
+                             "console",
+                             "data",
+                             "data_deps",
+                             "depfile",
+                             "deps",
+                             "outputs",
+                             "sources",
+                             "visibility",
+                           ])
+  }
+}
diff --git a/build/util/java_action.py b/build/util/java_action.py
new file mode 100755
index 0000000..abf084c
--- /dev/null
+++ b/build/util/java_action.py
@@ -0,0 +1,82 @@
+#!/usr/bin/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.
+
+"""Wrapper script to run java command as action with gn."""
+
+import os
+import subprocess
+import sys
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+
+def IsExecutable(path):
+  """Returns whether file at |path| exists and is executable.
+
+  Args:
+    path: absolute or relative path to test.
+
+  Returns:
+    True if the file at |path| exists, False otherwise.
+  """
+  return os.path.isfile(path) and os.access(path, os.X_OK)
+
+
+def FindCommand(command):
+  """Looks up for |command| in PATH.
+
+  Args:
+    command: name of the command to lookup, if command is a relative or
+      absolute path (i.e. contains some path separator) then only that
+      path will be tested.
+
+  Returns:
+    Full path to command or None if the command was not found.
+
+    On Windows, this respects the PATHEXT environment variable when the
+    command name does not have an extension.
+  """
+  fpath, _ = os.path.split(command)
+  if fpath:
+    if IsExecutable(command):
+      return command
+
+  if sys.platform == 'win32':
+    # On Windows, if the command does not have an extension, cmd.exe will
+    # try all extensions from PATHEXT when resolving the full path.
+    command, ext = os.path.splitext(command)
+    if not ext:
+      exts = os.environ['PATHEXT'].split(os.path.pathsep)
+    else:
+      exts = [ext]
+  else:
+    exts = ['']
+
+  for path in os.environ['PATH'].split(os.path.pathsep):
+    for ext in exts:
+      path = os.path.join(path, command) + ext
+      if IsExecutable(path):
+        return path
+
+  return None
+
+
+def main():
+  java_path = FindCommand('java')
+  if not java_path:
+    sys.stderr.write('java: command not found\n')
+    sys.exit(EXIT_FAILURE)
+
+  args = sys.argv[1:]
+  if len(args) < 2 or args[0] != '-jar':
+    sys.stderr.write('usage: %s -jar JARPATH [java_args]...\n' % sys.argv[0])
+    sys.exit(EXIT_FAILURE)
+
+  return subprocess.check_call([java_path] + args)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/util/lastchange.py b/build/util/lastchange.py
index 1a7f519..c81e0bd 100755
--- a/build/util/lastchange.py
+++ b/build/util/lastchange.py
@@ -90,7 +90,7 @@
     return None
 
 
-def FetchGitRevision(directory):
+def FetchGitRevision(directory, hash_only):
   """
   Fetch the Git hash for a given directory.
 
@@ -100,7 +100,10 @@
     A VersionInfo object or None on error.
   """
   hsh = ''
-  proc = RunGitCommand(directory, ['rev-parse', 'HEAD'])
+  git_args = ['log', '-1', '--format=%H']
+  if hash_only:
+    git_args.append('--grep=^Cr-Commit-Position:')
+  proc = RunGitCommand(directory, git_args)
   if proc:
     output = proc.communicate()[0].strip()
     if proc.returncode == 0 and output:
@@ -108,7 +111,7 @@
   if not hsh:
     return None
   pos = ''
-  proc = RunGitCommand(directory, ['cat-file', 'commit', 'HEAD'])
+  proc = RunGitCommand(directory, ['cat-file', 'commit', hsh])
   if proc:
     output = proc.communicate()[0]
     if proc.returncode == 0 and output:
@@ -116,12 +119,12 @@
         if line.startswith('Cr-Commit-Position:'):
           pos = line.rsplit()[-1].strip()
           break
-  if not pos:
+  if hash_only or not pos:
     return VersionInfo('git', hsh)
   return VersionInfo('git', '%s-%s' % (hsh, pos))
 
 
-def FetchGitSVNURLAndRevision(directory, svn_url_regex):
+def FetchGitSVNURLAndRevision(directory, svn_url_regex, go_deeper):
   """
   Fetch the Subversion URL and revision through Git.
 
@@ -130,7 +133,10 @@
   Returns:
     A tuple containing the Subversion URL and revision.
   """
-  proc = RunGitCommand(directory, ['log', '-1', '--format=%b'])
+  git_args = ['log', '-1', '--format=%b']
+  if go_deeper:
+    git_args.append('--grep=git-svn-id')
+  proc = RunGitCommand(directory, git_args)
   if proc:
     output = proc.communicate()[0].strip()
     if proc.returncode == 0 and output:
@@ -149,20 +155,21 @@
   return None, None
 
 
-def FetchGitSVNRevision(directory, svn_url_regex):
+def FetchGitSVNRevision(directory, svn_url_regex, go_deeper):
   """
   Fetch the Git-SVN identifier for the local tree.
 
   Errors are swallowed.
   """
-  url, revision = FetchGitSVNURLAndRevision(directory, svn_url_regex)
+  url, revision = FetchGitSVNURLAndRevision(directory, svn_url_regex, go_deeper)
   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'):
+                     directory_regex_prior_to_src_url='chrome|blink|svn',
+                     go_deeper=False, hash_only=False):
   """
   Returns the last change (in the form of a branch, revision tuple),
   from some appropriate revision control system.
@@ -171,8 +178,8 @@
       r'.*/(' + directory_regex_prior_to_src_url + r')(/.*)')
 
   version_info = (FetchSVNRevision(directory, svn_url_regex) or
-                  FetchGitSVNRevision(directory, svn_url_regex) or
-                  FetchGitRevision(directory))
+                  FetchGitSVNRevision(directory, svn_url_regex, go_deeper) or
+                  FetchGitRevision(directory, hash_only))
   if not version_info:
     if default_lastchange and os.path.exists(default_lastchange):
       revision = open(default_lastchange, 'r').read().strip()
@@ -256,6 +263,12 @@
                     "file-output-related options.")
   parser.add_option("-s", "--source-dir", metavar="DIR",
                     help="Use repository in the given directory.")
+  parser.add_option("--git-svn-go-deeper", action='store_true',
+                    help="In a Git-SVN repo, dig down to the last committed " +
+                    "SVN change (historic behaviour).")
+  parser.add_option("--git-hash-only", action="store_true",
+                    help="In a Git repo with commit positions, report only " +
+                    "the hash of the latest commit with a position.")
   opts, args = parser.parse_args(argv[1:])
 
   out_file = opts.output
@@ -274,7 +287,10 @@
   else:
     src_dir = os.path.dirname(os.path.abspath(__file__))
 
-  version_info = FetchVersionInfo(opts.default_lastchange, src_dir)
+  version_info = FetchVersionInfo(opts.default_lastchange,
+                                  directory=src_dir,
+                                  go_deeper=opts.git_svn_go_deeper,
+                                  hash_only=opts.git_hash_only)
 
   if version_info.revision == None:
     version_info.revision = '0'
diff --git a/build/util/lib/common/unittest_util.py b/build/util/lib/common/unittest_util.py
index e586224..189f587 100644
--- a/build/util/lib/common/unittest_util.py
+++ b/build/util/lib/common/unittest_util.py
@@ -129,7 +129,9 @@
     Filtered subset of the given list of test names.
   """
   pattern_groups = gtest_filter.split('-')
-  positive_patterns = pattern_groups[0].split(':')
+  positive_patterns = ['*']
+  if pattern_groups[0]:
+    positive_patterns = pattern_groups[0].split(':')
   negative_patterns = None
   if len(pattern_groups) > 1:
     negative_patterns = pattern_groups[1].split(':')
diff --git a/build/util/version.gni b/build/util/version.gni
new file mode 100644
index 0000000..fba8d25
--- /dev/null
+++ b/build/util/version.gni
@@ -0,0 +1,47 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This exposes the Chrome version as GN variables for use in build files.
+#
+# PREFER NOT TO USE THESE. The GYP build uses this kind of thing extensively.
+# However, it is far better to write an action (or use the process_version
+# wrapper in chrome/version.gni) to generate a file at build-time with the
+# information you need. This allows better dependency checking and GN will
+# run faster.
+#
+# These values should only be used if you REALLY need to depend on them at
+# build-time, for example, in the computation of output file names.
+
+# Give version.py a pattern that will expand to a GN scope consisting of
+# all values we need at once.
+_version_dictionary_template = "full = \"@MAJOR@.@MINOR@.@BUILD@.@PATCH@\" " +
+                               "major = \"@MAJOR@\" minor = \"@MINOR@\" " +
+                               "build = \"@BUILD@\" patch = \"@PATCH@\" " +
+                               "remoting = \"@REMOTING_PATCH\" "
+
+# The file containing the Chrome version number.
+chrome_version_file = "//chrome/VERSION"
+
+# The file containing the Chromoting version number.
+remoting_version_file = "//remoting/VERSION"
+
+_result = exec_script("version.py",
+                      [
+                        "-f",
+                        rebase_path(chrome_version_file, root_build_dir),
+                        "-t",
+                        _version_dictionary_template,
+                      ],
+                      "scope",
+                      [ chrome_version_file ])
+
+# Full version. For example "45.0.12321.0"
+chrome_version_full = _result.full
+
+# The consituent parts of the full version.
+chrome_version_major = _result.major
+chrome_version_minor = _result.minor
+chrome_version_build = _result.build
+chrome_version_patch = _result.patch
+remoting_version_patch = _result.remoting
diff --git a/build/util/webkit_version.h.in b/build/util/webkit_version.h.in
new file mode 100644
index 0000000..41960e7
--- /dev/null
+++ b/build/util/webkit_version.h.in
@@ -0,0 +1,9 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// webkit_version.h is generated from webkit_version.h.in.  Edit the source!
+
+#define WEBKIT_VERSION_MAJOR 537
+#define WEBKIT_VERSION_MINOR 36
+#define WEBKIT_SVN_REVISION "@@LASTCHANGE@"
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
old mode 100644
new mode 100755
index 5b175eb..723106b
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -1,3 +1,4 @@
+#!/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.
@@ -13,7 +14,6 @@
 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')
 
@@ -26,10 +26,13 @@
   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
+  vs_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:
+  # When running on a non-Windows host, only do this if the SDK has explicitly
+  # been downloaded before (in which case json_data_file will exist).
+  if ((sys.platform in ('win32', 'cygwin') or os.path.exists(json_data_file))
+      and depot_tools_win_toolchain):
     if not os.path.exists(json_data_file):
       Update()
     with open(json_data_file, 'r') as tempf:
@@ -37,12 +40,14 @@
 
     toolchain = toolchain_data['path']
     version = toolchain_data['version']
-    win8sdk = toolchain_data['win8sdk']
+    win_sdk = toolchain_data.get('win_sdk')
+    if not win_sdk:
+      win_sdk = 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']
+    vs_runtime_dll_dirs = toolchain_data['runtime_dirs']
 
     os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
     os.environ['GYP_MSVS_VERSION'] = version
@@ -51,15 +56,26 @@
     # otheroptions.express
     # values there.
     gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
-    gyp_defines_dict['windows_sdk_path'] = win8sdk
+    gyp_defines_dict['windows_sdk_path'] = win_sdk
     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['WINDOWSSDKDIR'] = win_sdk
     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)
+    runtime_path = ';'.join(vs_runtime_dll_dirs)
     os.environ['PATH'] = runtime_path + ';' + os.environ['PATH']
-  return vs2013_runtime_dll_dirs
+  return vs_runtime_dll_dirs
+
+
+def _VersionNumber():
+  """Gets the standard version number ('120', '140', etc.) based on
+  GYP_MSVS_VERSION."""
+  if os.environ['GYP_MSVS_VERSION'] == '2013':
+    return '120'
+  elif os.environ['GYP_MSVS_VERSION'] == '2015':
+    return '140'
+  else:
+    raise ValueError('Unexpected GYP_MSVS_VERSION')
 
 
 def _CopyRuntimeImpl(target, source):
@@ -75,14 +91,52 @@
     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 _CopyRuntime2013(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 file_part in ('p', 'r'):
+    dll = dll_pattern % file_part
+    target = os.path.join(target_dir, dll)
+    source = os.path.join(source_dir, dll)
+    _CopyRuntimeImpl(target, source)
+
+
+def _CopyRuntime2015(target_dir, source_dir, dll_pattern):
+  """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
+  exist, but the target directory does exist."""
+  for file_part in ('msvcp', 'vccorlib'):
+    dll = dll_pattern % file_part
+    target = os.path.join(target_dir, dll)
+    source = os.path.join(source_dir, dll)
+    _CopyRuntimeImpl(target, source)
+
+
+def _CopyRuntime(target_dir, source_dir, target_cpu, debug):
+  """Copy the VS runtime DLLs, only if the target doesn't exist, but the target
+  directory does exist. Handles VS 2013 and VS 2015."""
+  suffix = "d.dll" if debug else ".dll"
+  if os.environ.get('GYP_MSVS_VERSION') == '2015':
+    _CopyRuntime2015(target_dir, source_dir, '%s140' + suffix)
+  else:
+    _CopyRuntime2013(target_dir, source_dir, 'msvc%s120' + suffix)
+
+  # Copy the PGO runtime library to the release directories.
+  if not debug and 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 = 'pgort' + _VersionNumber() + '.dll'
+    if target_cpu == "x86":
+      source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
+      if os.path.exists(source_x86):
+        _CopyRuntimeImpl(os.path.join(target_dir, pgo_runtime_dll), source_x86)
+    elif target_cpu == "x64":
+      source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
+      if os.path.exists(source_x64):
+        _CopyRuntimeImpl(os.path.join(target_dir, pgo_runtime_dll),
+                          source_x64)
+    else:
+      raise NotImplementedError("Unexpected target_cpu value:" + target_cpu)
 
 
 def CopyVsRuntimeDlls(output_dir, runtime_dirs):
@@ -92,9 +146,9 @@
 
   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'))
 
+  This is used for the GYP build and gclient runhooks.
+  """
   x86, x64 = runtime_dirs
   out_debug = os.path.join(output_dir, 'Debug')
   out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
@@ -107,26 +161,12 @@
     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)
+  _CopyRuntime(out_debug,          x86, "x86", debug=True)
+  _CopyRuntime(out_release,        x86, "x86", debug=False)
+  _CopyRuntime(out_debug_x64,      x64, "x64", debug=True)
+  _CopyRuntime(out_release_x64,    x64, "x64", debug=False)
+  _CopyRuntime(out_debug_nacl64,   x64, "x64", debug=True)
+  _CopyRuntime(out_release_nacl64, x64, "x64", debug=False)
 
 
 def CopyDlls(target_dir, configuration, target_cpu):
@@ -137,34 +177,45 @@
 
   The debug configuration gets both the debug and release DLLs; the
   release config only the latter.
+
+  This is used for the GN build.
   """
-  vs2013_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
-  if not vs2013_runtime_dll_dirs:
+  vs_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
+  if not vs_runtime_dll_dirs:
     return
 
-  x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
+  x64_runtime, x86_runtime = vs_runtime_dll_dirs
   runtime_dir = x64_runtime if target_cpu == 'x64' else x86_runtime
-  _CopyRuntime(target_dir, runtime_dir, 'msvc%s120.dll')
+  _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=False)
   if configuration == 'Debug':
-    _CopyRuntime(target_dir, runtime_dir, 'msvc%s120d.dll')
+    _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=True)
 
 
 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()
+  if os.environ.get('GYP_MSVS_VERSION') == '2015':
+    return ['49ae4b60d898182fc3f521c2fcda82c453915011']
+  else:
+    # Default to VS2013.
+    return ['ee7d718ec60c2dc5d255bbe325909c2021a7efef']
 
 
-def Update():
+def Update(force=False):
   """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()|.
   """
+  if force != False and force != '--force':
+    print >>sys.stderr, 'Unknown parameter "%s"' % force
+    return 1
+  if force == '--force' or os.path.exists(json_data_file):
+    force = True
+
   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 ((sys.platform in ('win32', 'cygwin') or force) and
+        depot_tools_win_toolchain):
     import find_depot_tools
     depot_tools_path = find_depot_tools.add_depot_tools_to_path()
     get_toolchain_args = [
@@ -174,6 +225,8 @@
                     'get_toolchain_if_necessary.py'),
         '--output-json', json_data_file,
       ] + _GetDesiredVsToolchainHashes()
+    if force:
+      get_toolchain_args.append('--force')
     subprocess.check_call(get_toolchain_args)
 
   return 0
@@ -204,8 +257,6 @@
 
 
 def main():
-  if not sys.platform.startswith(('win32', 'cygwin')):
-    return 0
   commands = {
       'update': Update,
       'get_toolchain_dir': GetToolchainDir,
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index ea82f4e..22b86c3 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -136,7 +136,8 @@
 A herd of wild gits appears!  Time for CQ :D
 And one more for sizes.py...
 
-Sigh.
+What's an overmarketed dietary supplement expressing sadness, relief,
+tiredness, or a similar feeling.?  Ah-Sigh-ee.
 
 It was love at first sight.  The moment Yossarian first laid eyes on the chaplain, he fell madly in love with him.
 
@@ -154,3 +155,6 @@
 ^_^
 
 In the masters we don't.
+In the tryservers, we don't either.
+In the CQ sometimes.
+Auto-generated by git-eject-upstream (http://goo.gl/cIHsYR)
diff --git a/build/win/BUILD.gn b/build/win/BUILD.gn
new file mode 100644
index 0000000..466e7ee
--- /dev/null
+++ b/build/win/BUILD.gn
@@ -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.
+
+import("//build/config/win/manifest.gni")
+
+# Depending on this target will cause the manifests for Chrome's default
+# Windows and common control compatibility and elevation for executables.
+windows_manifest("default_exe_manifest") {
+  sources = [
+    as_invoker_manifest,
+    common_controls_manifest,
+    default_compatibility_manifest,
+  ]
+  type = "exe"
+}
diff --git a/build/win/as_invoker.manifest b/build/win/as_invoker.manifest
new file mode 100644
index 0000000..df046fd
--- /dev/null
+++ b/build/win/as_invoker.manifest
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+  <security>
+    <requestedPrivileges>
+      <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
+    </requestedPrivileges>
+  </security>
+</trustInfo></assembly>
diff --git a/build/win/asan.gyp b/build/win/asan.gyp
index c0d0c98..d938426 100644
--- a/build/win/asan.gyp
+++ b/build/win/asan.gyp
@@ -19,7 +19,7 @@
                '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',
+                 '<(DEPTH)/<(make_clang_dir)/lib/clang/<!(python <(DEPTH)/tools/clang/scripts/update.py --print-clang-version)/lib/windows/clang_rt.asan_dynamic-i386.dll',
                ],
              },
            ],
diff --git a/build/win/common_controls.manifest b/build/win/common_controls.manifest
new file mode 100644
index 0000000..1710196
--- /dev/null
+++ b/build/win/common_controls.manifest
@@ -0,0 +1,8 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*' />
+    </dependentAssembly>
+  </dependency>
+</assembly>
diff --git a/build/win/message_compiler.gni b/build/win/message_compiler.gni
new file mode 100644
index 0000000..1214898
--- /dev/null
+++ b/build/win/message_compiler.gni
@@ -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.
+
+assert(is_win, "This only runs on Windows.")
+
+# Runs mc.exe over a list of sources. The outputs (a header and rc file) are
+# placed in the target gen dir, and compiled.
+#
+# sources
+#   List of message files to process.
+#
+# user_mode_logging (optional bool)
+#   Generates user-mode logging code. Defaults to false (no logging code).
+#
+# deps, public_deps, visibility
+#   Normal meaning.
+template("message_compiler") {
+  action_name = "${target_name}_mc"
+  source_set_name = target_name
+
+  action_foreach(action_name) {
+    visibility = [ ":$source_set_name" ]
+
+    script = "//build/win/message_compiler.py"
+
+    outputs = [
+      "$target_gen_dir/{{source_name_part}}.h",
+      "$target_gen_dir/{{source_name_part}}.rc",
+    ]
+
+    args = [
+      # The first argument is the environment file saved to the build
+      # directory. This is required because the Windows toolchain setup saves
+      # the VC paths and such so that running "mc.exe" will work with the
+      # configured toolchain. This file is in the root build dir.
+      "environment.$current_cpu",
+
+      # 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),
+
+      # Input is Unicode.
+      "-u",
+    ]
+    if (defined(invoker.user_mode_logging) && invoker.user_mode_logging) {
+      args += [ "-um" ]
+    }
+    args += [ "{{source}}" ]
+
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "public_deps",
+                             "sources",
+                           ])
+  }
+
+  # Compile the generated rc file.
+  source_set(source_set_name) {
+    forward_variables_from(invoker, [ "visibility" ])
+    sources = get_target_outputs(":$action_name")
+    deps = [
+      ":$action_name",
+    ]
+  }
+}
diff --git a/build/win/message_compiler.py b/build/win/message_compiler.py
new file mode 100644
index 0000000..86aba4f
--- /dev/null
+++ b/build/win/message_compiler.py
@@ -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.
+
+# Runs the Microsoft Message Compiler (mc.exe). This Python adapter is for the
+# GN build, which can only run Python and not native binaries.
+#
+# Usage: message_compiler.py <environment_file> [<args to mc.exe>*]
+
+import subprocess
+import sys
+
+# Read the environment block from the file. This is stored in the format used
+# by CreateProcess. Drop last 2 NULs, one for list terminator, one for trailing
+# vs. separator.
+env_pairs = open(sys.argv[1]).read()[:-2].split('\0')
+env_dict = dict([item.split('=', 1) for item in env_pairs])
+
+# mc writes to stderr, so this explicitly redirects to stdout and eats it.
+try:
+  # This needs shell=True to search the path in env_dict for the mc executable.
+  subprocess.check_output(["mc.exe"] + sys.argv[2:],
+                          env=env_dict,
+                          stderr=subprocess.STDOUT,
+                          shell=True)
+except subprocess.CalledProcessError as e:
+  print e.output
+  sys.exit(e.returncode)
diff --git a/build/win/reorder-imports.py b/build/win/reorder-imports.py
index 281668f..00a69d7 100755
--- a/build/win/reorder-imports.py
+++ b/build/win/reorder-imports.py
@@ -31,7 +31,7 @@
 
   args.append('chrome_elf.dll');
 
-  subprocess.call(args)
+  subprocess.check_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)))
diff --git a/build/win/require_administrator.manifest b/build/win/require_administrator.manifest
new file mode 100644
index 0000000..4142e73
--- /dev/null
+++ b/build/win/require_administrator.manifest
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+  <security>
+    <requestedPrivileges>
+      <requestedExecutionLevel level="requireAdministrator" uiAccess="false"></requestedExecutionLevel>
+    </requestedPrivileges>
+  </security>
+</trustInfo></assembly>
diff --git a/build/win/use_ansi_codes.py b/build/win/use_ansi_codes.py
new file mode 100755
index 0000000..cff5f43
--- /dev/null
+++ b/build/win/use_ansi_codes.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+# 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.
+"""Prints if the the terminal is likely to understand ANSI codes."""
+
+import os
+
+# Add more terminals here as needed.
+print 'ANSICON' in os.environ
diff --git a/build/write_buildflag_header.py b/build/write_buildflag_header.py
new file mode 100755
index 0000000..d46cfc8
--- /dev/null
+++ b/build/write_buildflag_header.py
@@ -0,0 +1,95 @@
+#!/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.
+
+# This writes headers for build flags. See buildflag_header.gni for usage of
+# this system as a whole.
+#
+# The parameters are passed in a response file so we don't have to worry
+# about command line lengths. The name of the response file is passed on the
+# command line.
+#
+# The format of the response file is:
+#    [--flags <list of one or more flag values>]
+
+import optparse
+import os
+import shlex
+import sys
+
+
+class Options:
+  def __init__(self, output, rulename, header_guard, flags):
+    self.output = output
+    self.rulename = rulename
+    self.header_guard = header_guard
+    self.flags = flags
+
+
+def GetOptions():
+  parser = optparse.OptionParser()
+  parser.add_option('--output', help="Output header name inside --gen-dir.")
+  parser.add_option('--rulename',
+                    help="Helpful name of build rule for including in the " +
+                         "comment at the top of the file.")
+  parser.add_option('--gen-dir',
+                    help="Path to root of generated file directory tree.")
+  parser.add_option('--definitions',
+                    help="Name of the response file containing the flags.")
+  cmdline_options, cmdline_flags = parser.parse_args()
+
+  # Compute header guard by replacing some chars with _ and upper-casing.
+  header_guard = cmdline_options.output.upper()
+  header_guard = \
+      header_guard.replace('/', '_').replace('\\', '_').replace('.', '_')
+  header_guard += '_'
+
+  # The actual output file is inside the gen dir.
+  output = os.path.join(cmdline_options.gen_dir, cmdline_options.output)
+
+  # Definition file in GYP is newline separated, in GN they are shell formatted.
+  # shlex can parse both of these.
+  with open(cmdline_options.definitions, 'r') as def_file:
+    defs = shlex.split(def_file.read())
+  flags_index = defs.index('--flags')
+
+  # Everything after --flags are flags. true/false are remapped to 1/0,
+  # everything else is passed through.
+  flags = []
+  for flag in defs[flags_index + 1 :]:
+    equals_index = flag.index('=')
+    key = flag[:equals_index]
+    value = flag[equals_index + 1:]
+
+    # Canonicalize and validate the value.
+    if value == 'true':
+      value = '1'
+    elif value == 'false':
+      value = '0'
+    flags.append((key, str(value)))
+
+  return Options(output=output,
+                 rulename=cmdline_options.rulename,
+                 header_guard=header_guard,
+                 flags=flags)
+
+
+def WriteHeader(options):
+  with open(options.output, 'w') as output_file:
+    output_file.write("// Generated by build/write_buildflag_header.py\n")
+    if options.rulename:
+      output_file.write('// From "' + options.rulename + '"\n')
+
+    output_file.write('\n#ifndef %s\n' % options.header_guard)
+    output_file.write('#define %s\n\n' % options.header_guard)
+    output_file.write('#include "build/buildflag.h"\n\n')
+
+    for pair in options.flags:
+      output_file.write('#define BUILDFLAG_INTERNAL_%s() (%s)\n' % pair)
+
+    output_file.write('\n#endif  // %s\n' % options.header_guard)
+
+
+options = GetOptions()
+WriteHeader(options)
diff --git a/sandbox/BUILD.gn b/sandbox/BUILD.gn
index 15fb620..6825a1d 100644
--- a/sandbox/BUILD.gn
+++ b/sandbox/BUILD.gn
@@ -5,18 +5,18 @@
 # Meta-target that forwards to the proper platform one.
 group("sandbox") {
   if (is_win) {
-    deps = [
+    public_deps = [
       "//sandbox/win:sandbox",
     ]
   } else if (is_mac) {
     # TODO(GYP): Make sandbox compile w/ 10.6 SDK.
     if (false) {
-      deps = [
+      public_deps = [
         "//sandbox/mac:sandbox",
       ]
     }
   } else if (is_linux || is_android) {
-    deps = [
+    public_deps = [
       "//sandbox/linux:sandbox",
     ]
   }
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index 6cca0d3..5163425 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -3,8 +3,13 @@
 # found in the LICENSE file.
 
 import("//build/config/features.gni")
+import("//build/config/nacl/config.gni")
 import("//testing/test.gni")
 
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
 declare_args() {
   compile_suid_client = is_linux
 
@@ -14,21 +19,29 @@
   use_base_test_suite = is_linux
 }
 
+if (is_nacl_nonsfi) {
+  config("nacl_nonsfi_warnings") {
+    # There are number of platform specific functions in
+    # seccomp-bpf syscall helpers, which are not being used.
+    cflags = [ "-Wno-unused-function" ]
+  }
+}
+
 # We have two principal targets: sandbox and sandbox_linux_unittests
 # All other targets are listed as dependencies.
 # There is one notable exception: for historical reasons, chrome_sandbox is
 # the setuid sandbox and is its own target.
 
 group("sandbox") {
-  deps = [
+  public_deps = [
     ":sandbox_services",
   ]
 
-  if (compile_suid_client) {
-    deps += [ ":suid_sandbox_client" ]
+  if (compile_suid_client || is_nacl_nonsfi) {
+    public_deps += [ ":suid_sandbox_client" ]
   }
-  if (use_seccomp_bpf) {
-    deps += [
+  if (use_seccomp_bpf || is_nacl_nonsfi) {
+    public_deps += [
       ":seccomp_bpf",
       ":seccomp_bpf_helpers",
     ]
@@ -68,7 +81,7 @@
   }
 }
 
-# Sources shared by sandbox_linux_unittests and sandbox_linux_jni_unittests.
+# Sources for sandbox_linux_unittests.
 source_set("sandbox_linux_unittests_sources") {
   testonly = true
 
@@ -117,17 +130,24 @@
       "bpf_dsl/bpf_dsl_unittest.cc",
       "bpf_dsl/codegen_unittest.cc",
       "bpf_dsl/cons_unittest.cc",
+      "bpf_dsl/dump_bpf.cc",
+      "bpf_dsl/dump_bpf.h",
       "bpf_dsl/syscall_set_unittest.cc",
+      "bpf_dsl/test_trap_registry.cc",
+      "bpf_dsl/test_trap_registry.h",
+      "bpf_dsl/test_trap_registry_unittest.cc",
+      "bpf_dsl/verifier.cc",
+      "bpf_dsl/verifier.h",
       "integration_tests/bpf_dsl_seccomp_unittest.cc",
       "integration_tests/seccomp_broker_process_unittest.cc",
       "seccomp-bpf-helpers/baseline_policy_unittest.cc",
       "seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc",
       "seccomp-bpf/bpf_tests_unittest.cc",
-      "seccomp-bpf/errorcode_unittest.cc",
       "seccomp-bpf/sandbox_bpf_unittest.cc",
       "seccomp-bpf/syscall_unittest.cc",
       "seccomp-bpf/trap_unittest.cc",
     ]
+    deps += [ ":bpf_dsl_golden" ]
   }
   if (compile_credentials) {
     sources += [
@@ -146,23 +166,50 @@
   }
 }
 
-# The main sandboxing test target.
-test("sandbox_linux_unittests") {
+action("bpf_dsl_golden") {
+  script = "bpf_dsl/golden/generate.py"
+  inputs = [
+    "bpf_dsl/golden/i386/ArgSizePolicy.txt",
+    "bpf_dsl/golden/i386/BasicPolicy.txt",
+    "bpf_dsl/golden/i386/ElseIfPolicy.txt",
+    "bpf_dsl/golden/i386/MaskingPolicy.txt",
+    "bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt",
+    "bpf_dsl/golden/i386/NegativeConstantsPolicy.txt",
+    "bpf_dsl/golden/i386/SwitchPolicy.txt",
+    "bpf_dsl/golden/x86-64/ArgSizePolicy.txt",
+    "bpf_dsl/golden/x86-64/BasicPolicy.txt",
+    "bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt",
+    "bpf_dsl/golden/x86-64/ElseIfPolicy.txt",
+    "bpf_dsl/golden/x86-64/MaskingPolicy.txt",
+    "bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt",
+    "bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt",
+    "bpf_dsl/golden/x86-64/SwitchPolicy.txt",
+  ]
+  outputs = [
+    "$target_gen_dir/bpf_dsl/golden/golden_files.h",
+  ]
+  args =
+      rebase_path(outputs, root_build_dir) + rebase_path(inputs, root_build_dir)
+}
+
+# TODO(GYP): Delete this after we've converted everything to GN.
+# The _run targets exist only for compatibility w/ GYP.
+group("sandbox_linux_unittests_run") {
+  testonly = true
   deps = [
-    ":sandbox_linux_unittests_sources",
+    ":sandbox_linux_unittests",
   ]
 }
 
-# This target is the shared library used by Android APK (i.e.
-# JNI-friendly) tests.
-shared_library("sandbox_linux_jni_unittests") {
+# The main sandboxing test target. "sandbox_linux_unittests" cannot use the
+# test() template because the test is run as an executable not as an APK on
+# Android.
+executable("sandbox_linux_unittests") {
   testonly = true
   deps = [
     ":sandbox_linux_unittests_sources",
+    "//build/config/sanitizers:deps",
   ]
-  if (is_android) {
-    deps += [ "//testing/android/native_test:native_test_native_code" ]
-  }
 }
 
 component("seccomp_bpf") {
@@ -174,8 +221,7 @@
     "bpf_dsl/codegen.cc",
     "bpf_dsl/codegen.h",
     "bpf_dsl/cons.h",
-    "bpf_dsl/dump_bpf.cc",
-    "bpf_dsl/dump_bpf.h",
+    "bpf_dsl/errorcode.h",
     "bpf_dsl/linux_syscall_ranges.h",
     "bpf_dsl/policy.cc",
     "bpf_dsl/policy.h",
@@ -185,12 +231,8 @@
     "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",
@@ -205,6 +247,19 @@
     ":sandbox_services_headers",
     "//base",
   ]
+
+  if (is_nacl_nonsfi) {
+    cflags = [ "-fgnu-inline-asm" ]
+    sources -= [
+      "bpf_dsl/bpf_dsl_forward.h",
+      "bpf_dsl/bpf_dsl_impl.h",
+      "bpf_dsl/cons.h",
+      "bpf_dsl/errorcode.h",
+      "bpf_dsl/linux_syscall_ranges.h",
+      "bpf_dsl/seccomp_macros.h",
+      "bpf_dsl/trap_registry.h",
+    ]
+  }
 }
 
 component("seccomp_bpf_helpers") {
@@ -221,10 +276,20 @@
   defines = [ "SANDBOX_IMPLEMENTATION" ]
 
   deps = [
-    "//base",
     ":sandbox_services",
     ":seccomp_bpf",
+    "//base",
   ]
+
+  if (is_nacl_nonsfi) {
+    sources -= [
+      "seccomp-bpf-helpers/baseline_policy.cc",
+      "seccomp-bpf-helpers/baseline_policy.h",
+      "seccomp-bpf-helpers/syscall_sets.cc",
+      "seccomp-bpf-helpers/syscall_sets.h",
+    ]
+    configs += [ ":nacl_nonsfi_warnings" ]
+  }
 }
 
 if (is_linux) {
@@ -246,6 +311,10 @@
       # TODO fix this and re-enable this warning.
       "-Wno-sign-compare",
     ]
+
+    deps = [
+      "//build/config/sanitizers:deps",
+    ]
   }
 }
 
@@ -286,7 +355,7 @@
     "//base",
   ]
 
-  if (compile_credentials) {
+  if (compile_credentials || is_nacl_nonsfi) {
     sources += [
       "services/credentials.cc",
       "services/credentials.h",
@@ -298,6 +367,32 @@
 
     deps += [ ":sandbox_services_headers" ]
   }
+
+  if (is_nacl_nonsfi) {
+    cflags = [ "-fgnu-inline-asm" ]
+
+    sources -= [
+      "services/init_process_reaper.cc",
+      "services/init_process_reaper.h",
+      "services/scoped_process.cc",
+      "services/scoped_process.h",
+      "services/yama.cc",
+      "services/yama.h",
+      "syscall_broker/broker_channel.cc",
+      "syscall_broker/broker_channel.h",
+      "syscall_broker/broker_client.cc",
+      "syscall_broker/broker_client.h",
+      "syscall_broker/broker_common.h",
+      "syscall_broker/broker_file_permission.cc",
+      "syscall_broker/broker_file_permission.h",
+      "syscall_broker/broker_host.cc",
+      "syscall_broker/broker_host.h",
+      "syscall_broker/broker_policy.cc",
+      "syscall_broker/broker_policy.h",
+      "syscall_broker/broker_process.cc",
+      "syscall_broker/broker_process.h",
+    ]
+  }
 }
 
 source_set("sandbox_services_headers") {
@@ -311,24 +406,14 @@
     "system_headers/linux_seccomp.h",
     "system_headers/linux_signal.h",
     "system_headers/linux_syscalls.h",
+    "system_headers/linux_time.h",
     "system_headers/linux_ucontext.h",
     "system_headers/x86_32_linux_syscalls.h",
     "system_headers/x86_64_linux_syscalls.h",
   ]
 }
 
-# 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) {
+if (compile_suid_client || is_nacl_nonsfi) {
   component("suid_sandbox_client") {
     sources = [
       "suid/client/setuid_sandbox_client.cc",
@@ -344,38 +429,36 @@
       ":sandbox_services",
       "//base",
     ]
+
+    if (is_nacl_nonsfi) {
+      sources -= [
+        "suid/client/setuid_sandbox_host.cc",
+        "suid/client/setuid_sandbox_host.h",
+        "suid/common/sandbox.h",
+        "suid/common/suid_unsafe_environment_variables.h",
+      ]
+    }
   }
 }
 
 if (is_android) {
-  # TODO(GYP) 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' ],
-  #      }
+  create_native_executable_dist("sandbox_linux_unittests_deps") {
+    testonly = true
+    dist_dir = "$root_out_dir/sandbox_linux_unittests_deps"
+    binary = "$root_out_dir/sandbox_linux_unittests"
+    deps = [
+      ":sandbox_linux_unittests",
+    ]
+
+    if (is_component_build) {
+      deps += [ "//build/android:cpplib_stripped" ]
+    }
+  }
+
+  test_runner_script("sandbox_linux_unittests__test_runner_script") {
+    test_name = "sandbox_linux_unittests"
+    test_type = "gtest"
+    test_suite = "sandbox_linux_unittests"
+    isolate_file = "//sandbox/sandbox_linux_unittests_android.isolate"
+  }
 }
diff --git a/sandbox/linux/OWNERS b/sandbox/linux/OWNERS
index f39e967..99ef1bd 100644
--- a/sandbox/linux/OWNERS
+++ b/sandbox/linux/OWNERS
@@ -1,3 +1,4 @@
 jln@chromium.org
 jorgelo@chromium.org
 mdempsky@chromium.org
+rickyz@chromium.org
diff --git a/sandbox/linux/bpf_dsl/DEPS b/sandbox/linux/bpf_dsl/DEPS
index be37a12..70d9b18 100644
--- a/sandbox/linux/bpf_dsl/DEPS
+++ b/sandbox/linux/bpf_dsl/DEPS
@@ -1,5 +1,3 @@
 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
index 3a35903..100cc8b 100644
--- a/sandbox/linux/bpf_dsl/bpf_dsl.cc
+++ b/sandbox/linux/bpf_dsl/bpf_dsl.cc
@@ -9,68 +9,38 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/errorcode.h"
 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
-#include "sandbox/linux/seccomp-bpf/die.h"
-#include "sandbox/linux/seccomp-bpf/errorcode.h"
+#include "sandbox/linux/system_headers/linux_seccomp.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 {
+class ReturnResultExprImpl : public internal::ResultExprImpl {
  public:
-  AllowResultExprImpl() {}
+  explicit ReturnResultExprImpl(uint32_t ret) : ret_(ret) {}
 
-  ErrorCode Compile(PolicyCompiler* pc) const override {
-    return ErrorCode(ErrorCode::ERR_ALLOWED);
+  CodeGen::Node Compile(PolicyCompiler* pc) const override {
+    return pc->Return(ret_);
   }
 
-  bool IsAllow() const override { return true; }
+  bool IsAllow() const override { return IsAction(SECCOMP_RET_ALLOW); }
 
- 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_);
+  bool IsDeny() const override {
+    return IsAction(SECCOMP_RET_ERRNO) || IsAction(SECCOMP_RET_KILL);
   }
 
  private:
-  ~TraceResultExprImpl() override {}
+  ~ReturnResultExprImpl() override {}
 
-  uint16_t aux_;
+  bool IsAction(uint32_t action) const {
+    return (ret_ & SECCOMP_RET_ACTION) == action;
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(TraceResultExprImpl);
+  uint32_t ret_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReturnResultExprImpl);
 };
 
 class TrapResultExprImpl : public internal::ResultExprImpl {
@@ -80,7 +50,7 @@
     DCHECK(func_);
   }
 
-  ErrorCode Compile(PolicyCompiler* pc) const override {
+  CodeGen::Node Compile(PolicyCompiler* pc) const override {
     return pc->Trap(func_, arg_, safe_);
   }
 
@@ -105,9 +75,12 @@
                        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));
+  CodeGen::Node Compile(PolicyCompiler* pc) const override {
+    // We compile the "then" and "else" expressions in separate statements so
+    // they have a defined sequencing.  See https://crbug.com/529480.
+    CodeGen::Node then_node = then_result_->Compile(pc);
+    CodeGen::Node else_node = else_result_->Compile(pc);
+    return cond_->Compile(pc, then_node, else_node);
   }
 
   bool HasUnsafeTraps() const override {
@@ -128,10 +101,10 @@
  public:
   ConstBoolExprImpl(bool value) : value_(value) {}
 
-  ErrorCode Compile(PolicyCompiler* pc,
-                    ErrorCode true_ec,
-                    ErrorCode false_ec) const override {
-    return value_ ? true_ec : false_ec;
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return value_ ? then_node : else_node;
   }
 
  private:
@@ -142,40 +115,39 @@
   DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl);
 };
 
-class PrimitiveBoolExprImpl : public internal::BoolExprImpl {
+class MaskedEqualBoolExprImpl : 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) {}
+  MaskedEqualBoolExprImpl(int argno,
+                          size_t width,
+                          uint64_t mask,
+                          uint64_t value)
+      : argno_(argno), width_(width), 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);
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return pc->MaskedEqual(argno_, width_, mask_, value_, then_node, else_node);
   }
 
  private:
-  ~PrimitiveBoolExprImpl() override {}
+  ~MaskedEqualBoolExprImpl() override {}
 
   int argno_;
-  ErrorCode::ArgType is_32bit_;
+  size_t width_;
   uint64_t mask_;
   uint64_t value_;
 
-  DISALLOW_COPY_AND_ASSIGN(PrimitiveBoolExprImpl);
+  DISALLOW_COPY_AND_ASSIGN(MaskedEqualBoolExprImpl);
 };
 
 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);
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return cond_->Compile(pc, else_node, then_node);
   }
 
  private:
@@ -191,10 +163,11 @@
   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);
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return lhs_->Compile(pc, rhs_->Compile(pc, then_node, else_node),
+                         else_node);
   }
 
  private:
@@ -211,10 +184,11 @@
   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));
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return lhs_->Compile(pc, then_node,
+                         rhs_->Compile(pc, then_node, else_node));
   }
 
  private:
@@ -255,31 +229,30 @@
 }
 
 BoolExpr ArgEq(int num, size_t size, uint64_t mask, uint64_t val) {
+  // If this is changed, update Arg<T>::EqualTo's static_cast rules
+  // accordingly.
   CHECK(size == 4 || size == 8);
 
-  // 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));
+  return BoolExpr(new const MaskedEqualBoolExprImpl(num, size, mask, val));
 }
 
 }  // namespace internal
 
 ResultExpr Allow() {
-  return ResultExpr(new const AllowResultExprImpl());
+  return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_ALLOW));
 }
 
 ResultExpr Error(int err) {
-  return ResultExpr(new const ErrorResultExprImpl(err));
+  CHECK(err >= ErrorCode::ERR_MIN_ERRNO && err <= ErrorCode::ERR_MAX_ERRNO);
+  return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_ERRNO + err));
 }
 
-ResultExpr Kill(const char* msg) {
-  return Trap(BPFFailure, msg);
+ResultExpr Kill() {
+  return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_KILL));
 }
 
 ResultExpr Trace(uint16_t aux) {
-  return ResultExpr(new const TraceResultExprImpl(aux));
+  return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_TRACE + aux));
 }
 
 ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl.h b/sandbox/linux/bpf_dsl/bpf_dsl.h
index 365e9b5..913ab9c 100644
--- a/sandbox/linux/bpf_dsl/bpf_dsl.h
+++ b/sandbox/linux/bpf_dsl/bpf_dsl.h
@@ -55,7 +55,7 @@
 //
 // More generally, the DSL currently supports the following grammar:
 //
-//   result = Allow() | Error(errno) | Kill(msg) | Trace(aux)
+//   result = Allow() | Error(errno) | Kill() | Trace(aux)
 //          | Trap(trap_func, aux) | UnsafeTrap(trap_func, aux)
 //          | If(bool, result)[.ElseIf(bool, result)].Else(result)
 //          | Switch(arg)[.Case(val, result)].Default(result)
@@ -89,8 +89,8 @@
 // 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);
+// Kill specifies a result to kill the process (task) immediately.
+SANDBOX_EXPORT ResultExpr Kill();
 
 // Trace specifies a result to notify a tracing process via the
 // PTRACE_EVENT_SECCOMP event and allow it to change or skip the system call.
@@ -278,6 +278,10 @@
 // see http://www.parashift.com/c++-faq-lite/template-friends.html.
 template <typename T>
 BoolExpr Arg<T>::EqualTo(T val) const {
+  if (sizeof(T) == 4) {
+    // Prevent sign-extension of negative int32_t values.
+    return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint32_t>(val));
+  }
   return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(val));
 }
 
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_impl.h b/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
index 2ffaf79..0064f8a 100644
--- a/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
+++ b/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
@@ -7,12 +7,12 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
 #include "sandbox/sandbox_export.h"
 
 namespace sandbox {
-class ErrorCode;
-
 namespace bpf_dsl {
+class ErrorCode;
 class PolicyCompiler;
 
 namespace internal {
@@ -20,12 +20,12 @@
 // 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
+  // Compile uses |pc| to emit a CodeGen::Node that conditionally continues
+  // to either |then_node| or |false_node|, depending on whether the represented
   // boolean expression is true or false.
-  virtual ErrorCode Compile(PolicyCompiler* pc,
-                            ErrorCode true_ec,
-                            ErrorCode false_ec) const = 0;
+  virtual CodeGen::Node Compile(PolicyCompiler* pc,
+                                CodeGen::Node then_node,
+                                CodeGen::Node else_node) const = 0;
 
  protected:
   BoolExprImpl() {}
@@ -39,9 +39,9 @@
 // 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;
+  // Compile uses |pc| to emit a CodeGen::Node that executes the
+  // represented result expression.
+  virtual CodeGen::Node Compile(PolicyCompiler* pc) const = 0;
 
   // HasUnsafeTraps returns whether the result expression is or recursively
   // contains an unsafe trap expression.
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc b/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc
index 398ec59..dff21e5 100644
--- a/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc
+++ b/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc
@@ -20,12 +20,13 @@
 #include "build/build_config.h"
 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
 #include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/dump_bpf.h"
+#include "sandbox/linux/bpf_dsl/golden/golden_files.h"
 #include "sandbox/linux/bpf_dsl/policy.h"
 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
-#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/bpf_dsl/test_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"
 
@@ -37,12 +38,12 @@
 
 // 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) {
+                                     uintptr_t p0 = 0,
+                                     uintptr_t p1 = 0,
+                                     uintptr_t p2 = 0,
+                                     uintptr_t p3 = 0,
+                                     uintptr_t p4 = 0,
+                                     uintptr_t p5 = 0) {
   // Made up program counter for syscall address.
   const uint64_t kFakePC = 0x543210;
 
@@ -58,64 +59,44 @@
   return data;
 }
 
-class FakeTrapRegistry : public TrapRegistry {
+class PolicyEmulator {
  public:
-  FakeTrapRegistry() : map_() {}
-  virtual ~FakeTrapRegistry() {}
+  PolicyEmulator(const golden::Golden& golden, const Policy& policy)
+      : program_() {
+    TestTrapRegistry traps;
+    program_ = PolicyCompiler(&policy, &traps).Compile();
 
-  uint16_t Add(TrapFnc fnc, const void* aux, bool safe) override {
-    EXPECT_TRUE(safe);
+    // TODO(mdempsky): Generalize to more arches.
+    const char* expected = nullptr;
+#if defined(ARCH_CPU_X86)
+    expected = golden.i386_dump;
+#elif defined(ARCH_CPU_X86_64)
+    expected = golden.x86_64_dump;
+#endif
 
-    const uint16_t next_id = map_.size() + 1;
-    return map_.insert(std::make_pair(Key(fnc, aux), next_id)).first->second;
+    if (expected != nullptr) {
+      const std::string actual = DumpBPF::StringPrintProgram(program_);
+      EXPECT_EQ(expected, actual);
+    } else {
+      LOG(WARNING) << "Missing golden file data entry";
+    }
   }
 
-  bool EnableUnsafeTraps() override {
-    ADD_FAILURE() << "Unimplemented";
-    return false;
+  ~PolicyEmulator() {}
+
+  void ExpectAllow(const struct arch_seccomp_data& data) const {
+    EXPECT_EQ(SECCOMP_RET_ALLOW, Emulate(data));
+  }
+
+  void ExpectErrno(uint16_t err, const struct arch_seccomp_data& data) const {
+    EXPECT_EQ(SECCOMP_RET_ERRNO | err, Emulate(data));
+  }
+
+  void ExpectKill(const struct arch_seccomp_data& data) const {
+    EXPECT_EQ(SECCOMP_RET_KILL, Emulate(data));
   }
 
  private:
-  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);
@@ -126,17 +107,7 @@
     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);
 };
@@ -152,7 +123,7 @@
     }
     if (sysno == __NR_setuid) {
       const Arg<uid_t> uid(0);
-      return If(uid != 42, Error(ESRCH)).Else(Error(ENOMEM));
+      return If(uid != 42, Kill()).Else(Allow());
     }
     return Allow();
   }
@@ -162,14 +133,13 @@
 };
 
 TEST(BPFDSL, Basic) {
-  BasicPolicy policy;
-  PolicyEmulator emulator(&policy);
+  PolicyEmulator emulator(golden::kBasicPolicy, BasicPolicy());
 
   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));
+  emulator.ExpectAllow(FakeSyscall(__NR_setuid, 42));
+  emulator.ExpectKill(FakeSyscall(__NR_setuid, 43));
 }
 
 /* On IA-32, socketpair() is implemented via socketcall(). :-( */
@@ -194,8 +164,7 @@
 };
 
 TEST(BPFDSL, BooleanLogic) {
-  BooleanLogicPolicy policy;
-  PolicyEmulator emulator(&policy);
+  PolicyEmulator emulator(golden::kBooleanLogicPolicy, BooleanLogicPolicy());
 
   const intptr_t kFakeSV = 0x12345;
 
@@ -239,8 +208,8 @@
 };
 
 TEST(BPFDSL, MoreBooleanLogic) {
-  MoreBooleanLogicPolicy policy;
-  PolicyEmulator emulator(&policy);
+  PolicyEmulator emulator(golden::kMoreBooleanLogicPolicy,
+                          MoreBooleanLogicPolicy());
 
   // Expect EPERM if any set to 0.
   emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 0, 5, 5));
@@ -277,13 +246,37 @@
 };
 
 TEST(BPFDSL, ArgSizeTest) {
-  ArgSizePolicy policy;
-  PolicyEmulator emulator(&policy);
+  PolicyEmulator emulator(golden::kArgSizePolicy, ArgSizePolicy());
 
   emulator.ExpectAllow(FakeSyscall(__NR_uname, 0));
   emulator.ExpectErrno(EPERM, FakeSyscall(__NR_uname, kDeadBeefAddr));
 }
 
+class NegativeConstantsPolicy : public Policy {
+ public:
+  NegativeConstantsPolicy() {}
+  ~NegativeConstantsPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_fcntl) {
+      const Arg<int> fd(0);
+      return If(fd == -314, Error(EPERM)).Else(Allow());
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NegativeConstantsPolicy);
+};
+
+TEST(BPFDSL, NegativeConstantsTest) {
+  PolicyEmulator emulator(golden::kNegativeConstantsPolicy,
+                          NegativeConstantsPolicy());
+
+  emulator.ExpectAllow(FakeSyscall(__NR_fcntl, -5, F_DUPFD));
+  emulator.ExpectAllow(FakeSyscall(__NR_fcntl, 20, F_DUPFD));
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_fcntl, -314, F_DUPFD));
+}
+
 #if 0
 // TODO(mdempsky): This is really an integration test.
 
@@ -343,8 +336,7 @@
 };
 
 TEST(BPFDSL, MaskTest) {
-  MaskingPolicy policy;
-  PolicyEmulator emulator(&policy);
+  PolicyEmulator emulator(golden::kMaskingPolicy, MaskingPolicy());
 
   for (uid_t uid = 0; uid < 0x100; ++uid) {
     const int expect_errno = (uid & 0xf) == 0 ? EINVAL : EACCES;
@@ -382,8 +374,7 @@
 };
 
 TEST(BPFDSL, ElseIfTest) {
-  ElseIfPolicy policy;
-  PolicyEmulator emulator(&policy);
+  PolicyEmulator emulator(golden::kElseIfPolicy, ElseIfPolicy());
 
   emulator.ExpectErrno(0, FakeSyscall(__NR_setuid, 0));
 
@@ -419,8 +410,7 @@
 };
 
 TEST(BPFDSL, SwitchTest) {
-  SwitchPolicy policy;
-  PolicyEmulator emulator(&policy);
+  PolicyEmulator emulator(golden::kSwitchPolicy, SwitchPolicy());
 
   const int kFakeSockFD = 42;
 
diff --git a/sandbox/linux/bpf_dsl/codegen.cc b/sandbox/linux/bpf_dsl/codegen.cc
index bc2c7a2..d9eaf20 100644
--- a/sandbox/linux/bpf_dsl/codegen.cc
+++ b/sandbox/linux/bpf_dsl/codegen.cc
@@ -54,9 +54,8 @@
 CodeGen::~CodeGen() {
 }
 
-void CodeGen::Compile(CodeGen::Node head, Program* out) {
-  DCHECK(out);
-  out->assign(program_.rbegin() + Offset(head), program_.rend());
+CodeGen::Program CodeGen::Compile(CodeGen::Node head) {
+  return Program(program_.rbegin() + Offset(head), program_.rend());
 }
 
 CodeGen::Node CodeGen::MakeInstruction(uint16_t code,
@@ -145,14 +144,14 @@
 // 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);
+  if (base::get<0>(lhs) != base::get<0>(rhs))
+    return base::get<0>(lhs) < base::get<0>(rhs);
+  if (base::get<1>(lhs) != base::get<1>(rhs))
+    return base::get<1>(lhs) < base::get<1>(rhs);
+  if (base::get<2>(lhs) != base::get<2>(rhs))
+    return base::get<2>(lhs) < base::get<2>(rhs);
+  if (base::get<3>(lhs) != base::get<3>(rhs))
+    return base::get<3>(lhs) < base::get<3>(rhs);
   return false;
 }
 
diff --git a/sandbox/linux/bpf_dsl/codegen.h b/sandbox/linux/bpf_dsl/codegen.h
index c2e1f93..03c3b23 100644
--- a/sandbox/linux/bpf_dsl/codegen.h
+++ b/sandbox/linux/bpf_dsl/codegen.h
@@ -44,10 +44,9 @@
 //
 //   // 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);
+//   CodeGen::Program program = gen.Compile(dag);
 //   const struct sock_fprog prog = {
-//     static_cast<unsigned short>(program->size()), &program[0] };
+//     static_cast<unsigned short>(program.size()), &program[0] };
 //   prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
 //
 class SANDBOX_EXPORT CodeGen {
@@ -78,10 +77,10 @@
 
   // 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);
+  Program Compile(Node head);
 
  private:
-  using MemoKey = Tuple<uint16_t, uint32_t, Node, Node>;
+  using MemoKey = base::Tuple<uint16_t, uint32_t, Node, Node>;
   struct MemoKeyLess {
     bool operator()(const MemoKey& lhs, const MemoKey& rhs) const;
   };
diff --git a/sandbox/linux/bpf_dsl/codegen_unittest.cc b/sandbox/linux/bpf_dsl/codegen_unittest.cc
index 5961822..ec2abc7 100644
--- a/sandbox/linux/bpf_dsl/codegen_unittest.cc
+++ b/sandbox/linux/bpf_dsl/codegen_unittest.cc
@@ -127,8 +127,7 @@
   // test case.
   void RunTest(CodeGen::Node head) {
     // Compile the program
-    CodeGen::Program program;
-    gen_.Compile(head, &program);
+    CodeGen::Program program = gen_.Compile(head);
 
     // Walk the program backwards, and compute the hash for each instruction.
     std::vector<Hash> prog_hashes(program.size());
diff --git a/sandbox/linux/bpf_dsl/dump_bpf.cc b/sandbox/linux/bpf_dsl/dump_bpf.cc
index d0c8f75..29d28a6 100644
--- a/sandbox/linux/bpf_dsl/dump_bpf.cc
+++ b/sandbox/linux/bpf_dsl/dump_bpf.cc
@@ -4,9 +4,14 @@
 
 #include "sandbox/linux/bpf_dsl/dump_bpf.h"
 
+#include <inttypes.h>
 #include <stdio.h>
 
+#include <string>
+
+#include "base/strings/stringprintf.h"
 #include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
 #include "sandbox/linux/bpf_dsl/trap_registry.h"
 #include "sandbox/linux/system_headers/linux_filter.h"
 #include "sandbox/linux/system_headers/linux_seccomp.h"
@@ -14,95 +19,138 @@
 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;
-    }
+namespace {
+
+const char* AluOpToken(uint32_t code) {
+  switch (BPF_OP(code)) {
+    case BPF_ADD:
+      return "+";
+    case BPF_SUB:
+      return "-";
+    case BPF_MUL:
+      return "*";
+    case BPF_DIV:
+      return "/";
+    case BPF_MOD:
+      return "%";
+    case BPF_OR:
+      return "|";
+    case BPF_XOR:
+      return "^";
+    case BPF_AND:
+      return "&";
+    case BPF_LSH:
+      return "<<";
+    case BPF_RSH:
+      return ">>";
+    default:
+      return "???";
   }
-  return;
+}
+
+const char* JmpOpToken(uint32_t code) {
+  switch (BPF_OP(code)) {
+    case BPF_JSET:
+      return "&";
+    case BPF_JEQ:
+      return "==";
+    case BPF_JGE:
+      return ">=";
+    default:
+      return "???";
+  }
+}
+
+const char* DataOffsetName(size_t off) {
+  switch (off) {
+    case SECCOMP_NR_IDX:
+      return "System call number";
+    case SECCOMP_ARCH_IDX:
+      return "Architecture";
+    case SECCOMP_IP_LSB_IDX:
+      return "Instruction pointer (LSB)";
+    case SECCOMP_IP_MSB_IDX:
+      return "Instruction pointer (MSB)";
+    default:
+      return "???";
+  }
+}
+
+void AppendInstruction(std::string* dst, size_t pc, const sock_filter& insn) {
+  base::StringAppendF(dst, "%3zu) ", pc);
+  switch (BPF_CLASS(insn.code)) {
+    case BPF_LD:
+      if (insn.code == BPF_LD + BPF_W + BPF_ABS) {
+        base::StringAppendF(dst, "LOAD %" PRIu32 "  // ", insn.k);
+        size_t maybe_argno =
+            (insn.k - offsetof(struct arch_seccomp_data, args)) /
+            sizeof(uint64_t);
+        if (maybe_argno < 6 && insn.k == SECCOMP_ARG_LSB_IDX(maybe_argno)) {
+          base::StringAppendF(dst, "Argument %zu (LSB)\n", maybe_argno);
+        } else if (maybe_argno < 6 &&
+                   insn.k == SECCOMP_ARG_MSB_IDX(maybe_argno)) {
+          base::StringAppendF(dst, "Argument %zu (MSB)\n", maybe_argno);
+        } else {
+          base::StringAppendF(dst, "%s\n", DataOffsetName(insn.k));
+        }
+      } else {
+        base::StringAppendF(dst, "Load ???\n");
+      }
+      break;
+    case BPF_JMP:
+      if (BPF_OP(insn.code) == BPF_JA) {
+        base::StringAppendF(dst, "JMP %zu\n", pc + insn.k + 1);
+      } else {
+        base::StringAppendF(
+            dst, "if A %s 0x%" PRIx32 "; then JMP %zu else JMP %zu\n",
+            JmpOpToken(insn.code), insn.k, pc + insn.jt + 1, pc + insn.jf + 1);
+      }
+      break;
+    case BPF_RET:
+      base::StringAppendF(dst, "RET 0x%" PRIx32 "  // ", insn.k);
+      if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP) {
+        base::StringAppendF(dst, "Trap #%" PRIu32 "\n",
+                            insn.k & SECCOMP_RET_DATA);
+      } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
+        base::StringAppendF(dst, "errno = %" PRIu32 "\n",
+                            insn.k & SECCOMP_RET_DATA);
+      } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE) {
+        base::StringAppendF(dst, "Trace #%" PRIu32 "\n",
+                            insn.k & SECCOMP_RET_DATA);
+      } else if (insn.k == SECCOMP_RET_ALLOW) {
+        base::StringAppendF(dst, "Allowed\n");
+      } else if (insn.k == SECCOMP_RET_KILL) {
+        base::StringAppendF(dst, "Kill\n");
+      } else {
+        base::StringAppendF(dst, "???\n");
+      }
+      break;
+    case BPF_ALU:
+      if (BPF_OP(insn.code) == BPF_NEG) {
+        base::StringAppendF(dst, "A := -A\n");
+      } else {
+        base::StringAppendF(dst, "A := A %s 0x%" PRIx32 "\n",
+                            AluOpToken(insn.code), insn.k);
+      }
+      break;
+    default:
+      base::StringAppendF(dst, "???\n");
+      break;
+  }
+}
+
+}  // namespace
+
+void DumpBPF::PrintProgram(const CodeGen::Program& program) {
+  fputs(StringPrintProgram(program).c_str(), stderr);
+}
+
+std::string DumpBPF::StringPrintProgram(const CodeGen::Program& program) {
+  std::string res;
+  for (size_t i = 0; i < program.size(); i++) {
+    AppendInstruction(&res, i + 1, program[i]);
+  }
+  return res;
 }
 
 }  // namespace bpf_dsl
diff --git a/sandbox/linux/bpf_dsl/dump_bpf.h b/sandbox/linux/bpf_dsl/dump_bpf.h
index cd12be7..a7db589 100644
--- a/sandbox/linux/bpf_dsl/dump_bpf.h
+++ b/sandbox/linux/bpf_dsl/dump_bpf.h
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <string>
+
 #include "sandbox/linux/bpf_dsl/codegen.h"
 #include "sandbox/sandbox_export.h"
 
@@ -12,6 +14,10 @@
  public:
   // PrintProgram writes |program| in a human-readable format to stderr.
   static void PrintProgram(const CodeGen::Program& program);
+
+  // StringPrintProgram writes |program| in a human-readable format to
+  // a std::string.
+  static std::string StringPrintProgram(const CodeGen::Program& program);
 };
 
 }  // namespace bpf_dsl
diff --git a/sandbox/linux/bpf_dsl/errorcode.h b/sandbox/linux/bpf_dsl/errorcode.h
new file mode 100644
index 0000000..611c27d
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/errorcode.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
+#define SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// TODO(mdempsky): Find a proper home for ERR_{MIN,MAX}_ERRNO and
+// remove this header.
+class SANDBOX_EXPORT ErrorCode {
+ public:
+  enum {
+    ERR_MIN_ERRNO = 0,
+#if defined(__mips__)
+    // MIPS only supports errno up to 1133
+    ERR_MAX_ERRNO = 1133,
+#else
+    // TODO(markus): Android only supports errno up to 255
+    // (crbug.com/181647).
+    ERR_MAX_ERRNO = 4095,
+#endif
+  };
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ErrorCode);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
diff --git a/sandbox/linux/bpf_dsl/golden/generate.py b/sandbox/linux/bpf_dsl/golden/generate.py
new file mode 100644
index 0000000..c3ed1d9
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/generate.py
@@ -0,0 +1,51 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+
+arches = ['i386', 'x86-64']
+
+goldens = {}
+
+for fn in sys.argv[2:]:
+  dir, name = fn.split('/')[-2:]
+  name = name.rstrip('.txt')
+  golden = goldens.setdefault(name, [None] * len(arches))
+  idx = arches.index(dir)
+  golden[idx] = open(fn).read()
+
+with open(sys.argv[1], 'w') as f:
+  f.write("""// Generated by sandbox/linux/bpf_dsl/golden/generate.py
+
+#ifndef SANDBOX_LINUX_BPF_DSL_GOLDEN_GOLDEN_FILES_H_
+#define SANDBOX_LINUX_BPF_DSL_GOLDEN_GOLDEN_FILES_H_
+
+namespace sandbox {
+namespace bpf_dsl {
+namespace golden {
+
+struct Golden {
+  const char* i386_dump;
+  const char* x86_64_dump;
+};
+
+""")
+
+  for name, datas in sorted(goldens.items()):
+    f.write("const Golden k%s = {\n" % name)
+    for data in datas:
+      if data is None:
+        f.write("  nullptr,\n")
+      else:
+        f.write("  \"%s\",\n" % data.replace("\n", "\\n\\\n"))
+    f.write("};\n\n")
+
+  f.write("""\
+}  // namespace golden
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_GOLDEN_GOLDEN_FILES_H_
+""")
diff --git a/sandbox/linux/bpf_dsl/golden/i386/ArgSizePolicy.txt b/sandbox/linux/bpf_dsl/golden/i386/ArgSizePolicy.txt
new file mode 100644
index 0000000..a4ab2a8
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/i386/ArgSizePolicy.txt
@@ -0,0 +1,15 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0x40000003; then JMP 3 else JMP 10
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 10 else JMP 5
+  5) if A >= 0x7b; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 15 else JMP 14
+  7) if A >= 0x7a; then JMP 8 else JMP 14
+  8) LOAD 20  // Argument 0 (MSB)
+  9) if A == 0x0; then JMP 11 else JMP 10
+ 10) RET 0x0  // Kill
+ 11) LOAD 16  // Argument 0 (LSB)
+ 12) if A == 0xdeadbeef; then JMP 13 else JMP 14
+ 13) RET 0x50001  // errno = 1
+ 14) RET 0x7fff0000  // Allowed
+ 15) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/i386/BasicPolicy.txt b/sandbox/linux/bpf_dsl/golden/i386/BasicPolicy.txt
new file mode 100644
index 0000000..a05cfb5
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/i386/BasicPolicy.txt
@@ -0,0 +1,22 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0x40000003; then JMP 3 else JMP 20
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 20 else JMP 5
+  5) if A >= 0x84; then JMP 6 else JMP 8
+  6) if A >= 0x85; then JMP 7 else JMP 10
+  7) if A >= 0x401; then JMP 22 else JMP 21
+  8) if A >= 0x17; then JMP 9 else JMP 21
+  9) if A >= 0x18; then JMP 21 else JMP 16
+ 10) LOAD 20  // Argument 0 (MSB)
+ 11) if A == 0x0; then JMP 12 else JMP 20
+ 12) LOAD 16  // Argument 0 (LSB)
+ 13) if A == 0x0; then JMP 15 else JMP 14
+ 14) RET 0x50016  // errno = 22
+ 15) RET 0x50001  // errno = 1
+ 16) LOAD 20  // Argument 0 (MSB)
+ 17) if A == 0x0; then JMP 18 else JMP 20
+ 18) LOAD 16  // Argument 0 (LSB)
+ 19) if A == 0x2a; then JMP 21 else JMP 20
+ 20) RET 0x0  // Kill
+ 21) RET 0x7fff0000  // Allowed
+ 22) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/i386/ElseIfPolicy.txt b/sandbox/linux/bpf_dsl/golden/i386/ElseIfPolicy.txt
new file mode 100644
index 0000000..c199147
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/i386/ElseIfPolicy.txt
@@ -0,0 +1,26 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0x40000003; then JMP 3 else JMP 18
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 18 else JMP 5
+  5) if A >= 0x18; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 26 else JMP 25
+  7) if A >= 0x17; then JMP 8 else JMP 25
+  8) LOAD 20  // Argument 0 (MSB)
+  9) if A == 0x0; then JMP 10 else JMP 18
+ 10) LOAD 16  // Argument 0 (LSB)
+ 11) if A & 0xfff; then JMP 12 else JMP 24
+ 12) LOAD 20  // Argument 0 (MSB)
+ 13) if A == 0x0; then JMP 14 else JMP 18
+ 14) LOAD 16  // Argument 0 (LSB)
+ 15) if A & 0xff0; then JMP 16 else JMP 23
+ 16) LOAD 20  // Argument 0 (MSB)
+ 17) if A == 0x0; then JMP 19 else JMP 18
+ 18) RET 0x0  // Kill
+ 19) LOAD 16  // Argument 0 (LSB)
+ 20) if A & 0xf00; then JMP 21 else JMP 22
+ 21) RET 0x5000d  // errno = 13
+ 22) RET 0x50011  // errno = 17
+ 23) RET 0x50016  // errno = 22
+ 24) RET 0x50000  // errno = 0
+ 25) RET 0x7fff0000  // Allowed
+ 26) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/i386/MaskingPolicy.txt b/sandbox/linux/bpf_dsl/golden/i386/MaskingPolicy.txt
new file mode 100644
index 0000000..e594576
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/i386/MaskingPolicy.txt
@@ -0,0 +1,30 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0x40000003; then JMP 3 else JMP 24
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 24 else JMP 5
+  5) if A >= 0x2f; then JMP 6 else JMP 9
+  6) if A >= 0x3a; then JMP 7 else JMP 8
+  7) if A >= 0x401; then JMP 30 else JMP 29
+  8) if A >= 0x39; then JMP 12 else JMP 29
+  9) if A >= 0x18; then JMP 10 else JMP 11
+ 10) if A >= 0x2e; then JMP 17 else JMP 29
+ 11) if A >= 0x17; then JMP 22 else JMP 29
+ 12) LOAD 20  // Argument 0 (MSB)
+ 13) if A == 0x0; then JMP 14 else JMP 24
+ 14) LOAD 16  // Argument 0 (LSB)
+ 15) A := A & 0xa5
+ 16) if A == 0xa0; then JMP 28 else JMP 27
+ 17) LOAD 20  // Argument 0 (MSB)
+ 18) if A == 0x0; then JMP 19 else JMP 24
+ 19) LOAD 16  // Argument 0 (LSB)
+ 20) A := A & 0xf0
+ 21) if A == 0xf0; then JMP 28 else JMP 27
+ 22) LOAD 20  // Argument 0 (MSB)
+ 23) if A == 0x0; then JMP 25 else JMP 24
+ 24) RET 0x0  // Kill
+ 25) LOAD 16  // Argument 0 (LSB)
+ 26) if A & 0xf; then JMP 27 else JMP 28
+ 27) RET 0x5000d  // errno = 13
+ 28) RET 0x50016  // errno = 22
+ 29) RET 0x7fff0000  // Allowed
+ 30) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt b/sandbox/linux/bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt
new file mode 100644
index 0000000..0e91064
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt
@@ -0,0 +1,37 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0x40000003; then JMP 3 else JMP 30
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 30 else JMP 5
+  5) if A >= 0xa5; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 37 else JMP 36
+  7) if A >= 0xa4; then JMP 8 else JMP 36
+  8) LOAD 20  // Argument 0 (MSB)
+  9) if A == 0x0; then JMP 10 else JMP 30
+ 10) LOAD 16  // Argument 0 (LSB)
+ 11) if A == 0x0; then JMP 35 else JMP 12
+ 12) LOAD 28  // Argument 1 (MSB)
+ 13) if A == 0x0; then JMP 14 else JMP 30
+ 14) LOAD 24  // Argument 1 (LSB)
+ 15) if A == 0x0; then JMP 35 else JMP 16
+ 16) LOAD 36  // Argument 2 (MSB)
+ 17) if A == 0x0; then JMP 18 else JMP 30
+ 18) LOAD 32  // Argument 2 (LSB)
+ 19) if A == 0x0; then JMP 35 else JMP 20
+ 20) LOAD 20  // Argument 0 (MSB)
+ 21) if A == 0x0; then JMP 22 else JMP 30
+ 22) LOAD 16  // Argument 0 (LSB)
+ 23) if A == 0x1; then JMP 24 else JMP 33
+ 24) LOAD 28  // Argument 1 (MSB)
+ 25) if A == 0x0; then JMP 26 else JMP 30
+ 26) LOAD 24  // Argument 1 (LSB)
+ 27) if A == 0x1; then JMP 28 else JMP 33
+ 28) LOAD 36  // Argument 2 (MSB)
+ 29) if A == 0x0; then JMP 31 else JMP 30
+ 30) RET 0x0  // Kill
+ 31) LOAD 32  // Argument 2 (LSB)
+ 32) if A == 0x1; then JMP 34 else JMP 33
+ 33) RET 0x50016  // errno = 22
+ 34) RET 0x5000b  // errno = 11
+ 35) RET 0x50001  // errno = 1
+ 36) RET 0x7fff0000  // Allowed
+ 37) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/i386/NegativeConstantsPolicy.txt b/sandbox/linux/bpf_dsl/golden/i386/NegativeConstantsPolicy.txt
new file mode 100644
index 0000000..38707e3
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/i386/NegativeConstantsPolicy.txt
@@ -0,0 +1,15 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0x40000003; then JMP 3 else JMP 10
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 10 else JMP 5
+  5) if A >= 0x38; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 15 else JMP 14
+  7) if A >= 0x37; then JMP 8 else JMP 14
+  8) LOAD 20  // Argument 0 (MSB)
+  9) if A == 0x0; then JMP 11 else JMP 10
+ 10) RET 0x0  // Kill
+ 11) LOAD 16  // Argument 0 (LSB)
+ 12) if A == 0xfffffec6; then JMP 13 else JMP 14
+ 13) RET 0x50001  // errno = 1
+ 14) RET 0x7fff0000  // Allowed
+ 15) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/i386/SwitchPolicy.txt b/sandbox/linux/bpf_dsl/golden/i386/SwitchPolicy.txt
new file mode 100644
index 0000000..22093c4
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/i386/SwitchPolicy.txt
@@ -0,0 +1,34 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0x40000003; then JMP 3 else JMP 28
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 28 else JMP 5
+  5) if A >= 0x38; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 34 else JMP 33
+  7) if A >= 0x37; then JMP 8 else JMP 33
+  8) LOAD 28  // Argument 1 (MSB)
+  9) if A == 0x0; then JMP 10 else JMP 28
+ 10) LOAD 24  // Argument 1 (LSB)
+ 11) if A == 0x3; then JMP 32 else JMP 12
+ 12) LOAD 28  // Argument 1 (MSB)
+ 13) if A == 0x0; then JMP 14 else JMP 28
+ 14) LOAD 24  // Argument 1 (LSB)
+ 15) if A == 0x1; then JMP 32 else JMP 16
+ 16) LOAD 28  // Argument 1 (MSB)
+ 17) if A == 0x0; then JMP 18 else JMP 28
+ 18) LOAD 24  // Argument 1 (LSB)
+ 19) if A == 0x2; then JMP 26 else JMP 20
+ 20) LOAD 28  // Argument 1 (MSB)
+ 21) if A == 0x0; then JMP 22 else JMP 28
+ 22) LOAD 24  // Argument 1 (LSB)
+ 23) if A == 0x4; then JMP 25 else JMP 24
+ 24) RET 0x5000d  // errno = 13
+ 25) RET 0x50001  // errno = 1
+ 26) LOAD 36  // Argument 2 (MSB)
+ 27) if A == 0x0; then JMP 29 else JMP 28
+ 28) RET 0x0  // Kill
+ 29) LOAD 32  // Argument 2 (LSB)
+ 30) if A == 0x80000; then JMP 33 else JMP 31
+ 31) RET 0x50016  // errno = 22
+ 32) RET 0x50002  // errno = 2
+ 33) RET 0x7fff0000  // Allowed
+ 34) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/x86-64/ArgSizePolicy.txt b/sandbox/linux/bpf_dsl/golden/x86-64/ArgSizePolicy.txt
new file mode 100644
index 0000000..ca1f610
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/x86-64/ArgSizePolicy.txt
@@ -0,0 +1,15 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0xc000003e; then JMP 3 else JMP 5
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 5 else JMP 6
+  5) RET 0x0  // Kill
+  6) if A >= 0x40; then JMP 7 else JMP 8
+  7) if A >= 0x401; then JMP 15 else JMP 14
+  8) if A >= 0x3f; then JMP 9 else JMP 14
+  9) LOAD 20  // Argument 0 (MSB)
+ 10) if A == 0xdeadbeef; then JMP 11 else JMP 14
+ 11) LOAD 16  // Argument 0 (LSB)
+ 12) if A == 0xdeadbeef; then JMP 13 else JMP 14
+ 13) RET 0x50001  // errno = 1
+ 14) RET 0x7fff0000  // Allowed
+ 15) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/x86-64/BasicPolicy.txt b/sandbox/linux/bpf_dsl/golden/x86-64/BasicPolicy.txt
new file mode 100644
index 0000000..f0f37e9
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/x86-64/BasicPolicy.txt
@@ -0,0 +1,28 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0xc000003e; then JMP 3 else JMP 26
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 26 else JMP 5
+  5) if A >= 0x79; then JMP 6 else JMP 8
+  6) if A >= 0x7a; then JMP 7 else JMP 10
+  7) if A >= 0x401; then JMP 28 else JMP 27
+  8) if A >= 0x69; then JMP 9 else JMP 27
+  9) if A >= 0x6a; then JMP 27 else JMP 19
+ 10) LOAD 20  // Argument 0 (MSB)
+ 11) if A == 0x0; then JMP 15 else JMP 12
+ 12) if A == 0xffffffff; then JMP 13 else JMP 26
+ 13) LOAD 16  // Argument 0 (LSB)
+ 14) if A & 0x80000000; then JMP 15 else JMP 26
+ 15) LOAD 16  // Argument 0 (LSB)
+ 16) if A == 0x0; then JMP 18 else JMP 17
+ 17) RET 0x50016  // errno = 22
+ 18) RET 0x50001  // errno = 1
+ 19) LOAD 20  // Argument 0 (MSB)
+ 20) if A == 0x0; then JMP 24 else JMP 21
+ 21) if A == 0xffffffff; then JMP 22 else JMP 26
+ 22) LOAD 16  // Argument 0 (LSB)
+ 23) if A & 0x80000000; then JMP 24 else JMP 26
+ 24) LOAD 16  // Argument 0 (LSB)
+ 25) if A == 0x2a; then JMP 27 else JMP 26
+ 26) RET 0x0  // Kill
+ 27) RET 0x7fff0000  // Allowed
+ 28) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt b/sandbox/linux/bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt
new file mode 100644
index 0000000..d6123f1
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt
@@ -0,0 +1,40 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0xc000003e; then JMP 3 else JMP 34
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 34 else JMP 5
+  5) if A >= 0x36; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 40 else JMP 39
+  7) if A >= 0x35; then JMP 8 else JMP 39
+  8) LOAD 20  // Argument 0 (MSB)
+  9) if A == 0x0; then JMP 13 else JMP 10
+ 10) if A == 0xffffffff; then JMP 11 else JMP 34
+ 11) LOAD 16  // Argument 0 (LSB)
+ 12) if A & 0x80000000; then JMP 13 else JMP 34
+ 13) LOAD 16  // Argument 0 (LSB)
+ 14) if A == 0x1; then JMP 15 else JMP 37
+ 15) LOAD 28  // Argument 1 (MSB)
+ 16) if A == 0x0; then JMP 20 else JMP 17
+ 17) if A == 0xffffffff; then JMP 18 else JMP 34
+ 18) LOAD 24  // Argument 1 (LSB)
+ 19) if A & 0x80000000; then JMP 20 else JMP 34
+ 20) LOAD 24  // Argument 1 (LSB)
+ 21) if A == 0x1; then JMP 29 else JMP 22
+ 22) LOAD 28  // Argument 1 (MSB)
+ 23) if A == 0x0; then JMP 27 else JMP 24
+ 24) if A == 0xffffffff; then JMP 25 else JMP 34
+ 25) LOAD 24  // Argument 1 (LSB)
+ 26) if A & 0x80000000; then JMP 27 else JMP 34
+ 27) LOAD 24  // Argument 1 (LSB)
+ 28) if A == 0x2; then JMP 29 else JMP 37
+ 29) LOAD 36  // Argument 2 (MSB)
+ 30) if A == 0x0; then JMP 35 else JMP 31
+ 31) if A == 0xffffffff; then JMP 32 else JMP 34
+ 32) LOAD 32  // Argument 2 (LSB)
+ 33) if A & 0x80000000; then JMP 35 else JMP 34
+ 34) RET 0x0  // Kill
+ 35) LOAD 32  // Argument 2 (LSB)
+ 36) if A == 0x0; then JMP 38 else JMP 37
+ 37) RET 0x50016  // errno = 22
+ 38) RET 0x50001  // errno = 1
+ 39) RET 0x7fff0000  // Allowed
+ 40) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/x86-64/ElseIfPolicy.txt b/sandbox/linux/bpf_dsl/golden/x86-64/ElseIfPolicy.txt
new file mode 100644
index 0000000..5dfc136
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/x86-64/ElseIfPolicy.txt
@@ -0,0 +1,35 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0xc000003e; then JMP 3 else JMP 27
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 27 else JMP 5
+  5) if A >= 0x6a; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 35 else JMP 34
+  7) if A >= 0x69; then JMP 8 else JMP 34
+  8) LOAD 20  // Argument 0 (MSB)
+  9) if A == 0x0; then JMP 13 else JMP 10
+ 10) if A == 0xffffffff; then JMP 11 else JMP 27
+ 11) LOAD 16  // Argument 0 (LSB)
+ 12) if A & 0x80000000; then JMP 13 else JMP 27
+ 13) LOAD 16  // Argument 0 (LSB)
+ 14) if A & 0xfff; then JMP 15 else JMP 33
+ 15) LOAD 20  // Argument 0 (MSB)
+ 16) if A == 0x0; then JMP 20 else JMP 17
+ 17) if A == 0xffffffff; then JMP 18 else JMP 27
+ 18) LOAD 16  // Argument 0 (LSB)
+ 19) if A & 0x80000000; then JMP 20 else JMP 27
+ 20) LOAD 16  // Argument 0 (LSB)
+ 21) if A & 0xff0; then JMP 22 else JMP 32
+ 22) LOAD 20  // Argument 0 (MSB)
+ 23) if A == 0x0; then JMP 28 else JMP 24
+ 24) if A == 0xffffffff; then JMP 25 else JMP 27
+ 25) LOAD 16  // Argument 0 (LSB)
+ 26) if A & 0x80000000; then JMP 28 else JMP 27
+ 27) RET 0x0  // Kill
+ 28) LOAD 16  // Argument 0 (LSB)
+ 29) if A & 0xf00; then JMP 30 else JMP 31
+ 30) RET 0x5000d  // errno = 13
+ 31) RET 0x50011  // errno = 17
+ 32) RET 0x50016  // errno = 22
+ 33) RET 0x50000  // errno = 0
+ 34) RET 0x7fff0000  // Allowed
+ 35) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/x86-64/MaskingPolicy.txt b/sandbox/linux/bpf_dsl/golden/x86-64/MaskingPolicy.txt
new file mode 100644
index 0000000..b6892c0
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/x86-64/MaskingPolicy.txt
@@ -0,0 +1,38 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0xc000003e; then JMP 3 else JMP 32
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 32 else JMP 5
+  5) if A >= 0x6b; then JMP 6 else JMP 9
+  6) if A >= 0x6e; then JMP 7 else JMP 8
+  7) if A >= 0x401; then JMP 38 else JMP 37
+  8) if A >= 0x6d; then JMP 11 else JMP 37
+  9) if A >= 0x69; then JMP 10 else JMP 37
+ 10) if A >= 0x6a; then JMP 19 else JMP 27
+ 11) LOAD 20  // Argument 0 (MSB)
+ 12) if A == 0x0; then JMP 16 else JMP 13
+ 13) if A == 0xffffffff; then JMP 14 else JMP 32
+ 14) LOAD 16  // Argument 0 (LSB)
+ 15) if A & 0x80000000; then JMP 16 else JMP 32
+ 16) LOAD 16  // Argument 0 (LSB)
+ 17) A := A & 0xa5
+ 18) if A == 0xa0; then JMP 36 else JMP 35
+ 19) LOAD 20  // Argument 0 (MSB)
+ 20) if A == 0x0; then JMP 24 else JMP 21
+ 21) if A == 0xffffffff; then JMP 22 else JMP 32
+ 22) LOAD 16  // Argument 0 (LSB)
+ 23) if A & 0x80000000; then JMP 24 else JMP 32
+ 24) LOAD 16  // Argument 0 (LSB)
+ 25) A := A & 0xf0
+ 26) if A == 0xf0; then JMP 36 else JMP 35
+ 27) LOAD 20  // Argument 0 (MSB)
+ 28) if A == 0x0; then JMP 33 else JMP 29
+ 29) if A == 0xffffffff; then JMP 30 else JMP 32
+ 30) LOAD 16  // Argument 0 (LSB)
+ 31) if A & 0x80000000; then JMP 33 else JMP 32
+ 32) RET 0x0  // Kill
+ 33) LOAD 16  // Argument 0 (LSB)
+ 34) if A & 0xf; then JMP 35 else JMP 36
+ 35) RET 0x5000d  // errno = 13
+ 36) RET 0x50016  // errno = 22
+ 37) RET 0x7fff0000  // Allowed
+ 38) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt b/sandbox/linux/bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt
new file mode 100644
index 0000000..b42e35d
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt
@@ -0,0 +1,55 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0xc000003e; then JMP 3 else JMP 48
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 48 else JMP 5
+  5) if A >= 0x76; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 55 else JMP 54
+  7) if A >= 0x75; then JMP 8 else JMP 54
+  8) LOAD 20  // Argument 0 (MSB)
+  9) if A == 0x0; then JMP 13 else JMP 10
+ 10) if A == 0xffffffff; then JMP 11 else JMP 48
+ 11) LOAD 16  // Argument 0 (LSB)
+ 12) if A & 0x80000000; then JMP 13 else JMP 48
+ 13) LOAD 16  // Argument 0 (LSB)
+ 14) if A == 0x0; then JMP 53 else JMP 15
+ 15) LOAD 28  // Argument 1 (MSB)
+ 16) if A == 0x0; then JMP 20 else JMP 17
+ 17) if A == 0xffffffff; then JMP 18 else JMP 48
+ 18) LOAD 24  // Argument 1 (LSB)
+ 19) if A & 0x80000000; then JMP 20 else JMP 48
+ 20) LOAD 24  // Argument 1 (LSB)
+ 21) if A == 0x0; then JMP 53 else JMP 22
+ 22) LOAD 36  // Argument 2 (MSB)
+ 23) if A == 0x0; then JMP 27 else JMP 24
+ 24) if A == 0xffffffff; then JMP 25 else JMP 48
+ 25) LOAD 32  // Argument 2 (LSB)
+ 26) if A & 0x80000000; then JMP 27 else JMP 48
+ 27) LOAD 32  // Argument 2 (LSB)
+ 28) if A == 0x0; then JMP 53 else JMP 29
+ 29) LOAD 20  // Argument 0 (MSB)
+ 30) if A == 0x0; then JMP 34 else JMP 31
+ 31) if A == 0xffffffff; then JMP 32 else JMP 48
+ 32) LOAD 16  // Argument 0 (LSB)
+ 33) if A & 0x80000000; then JMP 34 else JMP 48
+ 34) LOAD 16  // Argument 0 (LSB)
+ 35) if A == 0x1; then JMP 36 else JMP 51
+ 36) LOAD 28  // Argument 1 (MSB)
+ 37) if A == 0x0; then JMP 41 else JMP 38
+ 38) if A == 0xffffffff; then JMP 39 else JMP 48
+ 39) LOAD 24  // Argument 1 (LSB)
+ 40) if A & 0x80000000; then JMP 41 else JMP 48
+ 41) LOAD 24  // Argument 1 (LSB)
+ 42) if A == 0x1; then JMP 43 else JMP 51
+ 43) LOAD 36  // Argument 2 (MSB)
+ 44) if A == 0x0; then JMP 49 else JMP 45
+ 45) if A == 0xffffffff; then JMP 46 else JMP 48
+ 46) LOAD 32  // Argument 2 (LSB)
+ 47) if A & 0x80000000; then JMP 49 else JMP 48
+ 48) RET 0x0  // Kill
+ 49) LOAD 32  // Argument 2 (LSB)
+ 50) if A == 0x1; then JMP 52 else JMP 51
+ 51) RET 0x50016  // errno = 22
+ 52) RET 0x5000b  // errno = 11
+ 53) RET 0x50001  // errno = 1
+ 54) RET 0x7fff0000  // Allowed
+ 55) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt b/sandbox/linux/bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt
new file mode 100644
index 0000000..6c0c7c1
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt
@@ -0,0 +1,18 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0xc000003e; then JMP 3 else JMP 13
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 13 else JMP 5
+  5) if A >= 0x49; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 18 else JMP 17
+  7) if A >= 0x48; then JMP 8 else JMP 17
+  8) LOAD 20  // Argument 0 (MSB)
+  9) if A == 0x0; then JMP 14 else JMP 10
+ 10) if A == 0xffffffff; then JMP 11 else JMP 13
+ 11) LOAD 16  // Argument 0 (LSB)
+ 12) if A & 0x80000000; then JMP 14 else JMP 13
+ 13) RET 0x0  // Kill
+ 14) LOAD 16  // Argument 0 (LSB)
+ 15) if A == 0xfffffec6; then JMP 16 else JMP 17
+ 16) RET 0x50001  // errno = 1
+ 17) RET 0x7fff0000  // Allowed
+ 18) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/golden/x86-64/SwitchPolicy.txt b/sandbox/linux/bpf_dsl/golden/x86-64/SwitchPolicy.txt
new file mode 100644
index 0000000..21055bb
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/golden/x86-64/SwitchPolicy.txt
@@ -0,0 +1,46 @@
+  1) LOAD 4  // Architecture
+  2) if A == 0xc000003e; then JMP 3 else JMP 34
+  3) LOAD 0  // System call number
+  4) if A & 0x40000000; then JMP 34 else JMP 5
+  5) if A >= 0x49; then JMP 6 else JMP 7
+  6) if A >= 0x401; then JMP 46 else JMP 45
+  7) if A >= 0x48; then JMP 8 else JMP 45
+  8) LOAD 28  // Argument 1 (MSB)
+  9) if A == 0x0; then JMP 13 else JMP 10
+ 10) if A == 0xffffffff; then JMP 11 else JMP 34
+ 11) LOAD 24  // Argument 1 (LSB)
+ 12) if A & 0x80000000; then JMP 13 else JMP 34
+ 13) LOAD 24  // Argument 1 (LSB)
+ 14) if A == 0x3; then JMP 44 else JMP 15
+ 15) LOAD 28  // Argument 1 (MSB)
+ 16) if A == 0x0; then JMP 20 else JMP 17
+ 17) if A == 0xffffffff; then JMP 18 else JMP 34
+ 18) LOAD 24  // Argument 1 (LSB)
+ 19) if A & 0x80000000; then JMP 20 else JMP 34
+ 20) LOAD 24  // Argument 1 (LSB)
+ 21) if A == 0x1; then JMP 44 else JMP 22
+ 22) LOAD 28  // Argument 1 (MSB)
+ 23) if A == 0x0; then JMP 27 else JMP 24
+ 24) if A == 0xffffffff; then JMP 25 else JMP 34
+ 25) LOAD 24  // Argument 1 (LSB)
+ 26) if A & 0x80000000; then JMP 27 else JMP 34
+ 27) LOAD 24  // Argument 1 (LSB)
+ 28) if A == 0x2; then JMP 39 else JMP 29
+ 29) LOAD 28  // Argument 1 (MSB)
+ 30) if A == 0x0; then JMP 35 else JMP 31
+ 31) if A == 0xffffffff; then JMP 32 else JMP 34
+ 32) LOAD 24  // Argument 1 (LSB)
+ 33) if A & 0x80000000; then JMP 35 else JMP 34
+ 34) RET 0x0  // Kill
+ 35) LOAD 24  // Argument 1 (LSB)
+ 36) if A == 0x4; then JMP 38 else JMP 37
+ 37) RET 0x5000d  // errno = 13
+ 38) RET 0x50001  // errno = 1
+ 39) LOAD 36  // Argument 2 (MSB)
+ 40) if A == 0x0; then JMP 41 else JMP 43
+ 41) LOAD 32  // Argument 2 (LSB)
+ 42) if A == 0x80000; then JMP 45 else JMP 43
+ 43) RET 0x50016  // errno = 22
+ 44) RET 0x50002  // errno = 2
+ 45) RET 0x7fff0000  // Allowed
+ 46) RET 0x50026  // errno = 38
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc
index f38232f..a4a842b 100644
--- a/sandbox/linux/bpf_dsl/policy_compiler.cc
+++ b/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -14,12 +14,9 @@
 #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"
@@ -56,6 +53,10 @@
   return x != 0 && (x & (x - 1)) == 0;
 }
 
+ResultExpr DefaultPanic(const char* error) {
+  return Kill();
+}
+
 // A Trap() handler that returns an "errno" value. The value is encoded
 // in the "aux" parameter.
 intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) {
@@ -88,7 +89,7 @@
     : policy_(policy),
       registry_(registry),
       escapepc_(0),
-      conds_(),
+      panic_func_(DefaultPanic),
       gen_(),
       has_unsafe_traps_(HasUnsafeTraps(policy_)) {
   DCHECK(policy);
@@ -97,7 +98,7 @@
 PolicyCompiler::~PolicyCompiler() {
 }
 
-scoped_ptr<CodeGen::Program> PolicyCompiler::Compile(bool verify) {
+CodeGen::Program PolicyCompiler::Compile() {
   CHECK(policy_->InvalidSyscall()->IsDeny())
       << "Policies should deny invalid system calls";
 
@@ -116,27 +117,17 @@
   }
 
   // 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();
+  return gen_.Compile(AssemblePolicy());
 }
 
 void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) {
   escapepc_ = escapepc;
 }
 
+void PolicyCompiler::SetPanicFunc(PanicFunc panic_func) {
+  panic_func_ = panic_func;
+}
+
 CodeGen::Node PolicyCompiler::AssemblePolicy() {
   // A compiled policy consists of three logical parts:
   //   1. Check that the "arch" field matches the expected architecture.
@@ -152,9 +143,9 @@
   // 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"))));
+      gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed,
+                           CompileResult(panic_func_(
+                               "Invalid audit architecture in BPF filter"))));
 }
 
 CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) {
@@ -190,7 +181,7 @@
 }
 
 CodeGen::Node PolicyCompiler::DispatchSyscall() {
-  // Evaluate all possible system calls and group their ErrorCodes into
+  // Evaluate all possible system calls and group their Nodes into
   // ranges of identical codes.
   Ranges ranges;
   FindRanges(&ranges);
@@ -209,7 +200,7 @@
     // 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"));
+        CompileResult(panic_func_("Illegal mixing of system call ABIs"));
     if (kIsX32) {
       // The newer x32 API always sets bit 30.
       return gen_.MakeInstruction(
@@ -230,7 +221,7 @@
   // 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.
+  // negative) all return the same Node.
   const CodeGen::Node invalid_node = CompileResult(policy_->InvalidSyscall());
   uint32_t old_sysnum = 0;
   CodeGen::Node old_node =
@@ -282,68 +273,54 @@
 }
 
 CodeGen::Node PolicyCompiler::CompileResult(const ResultExpr& res) {
-  return RetExpression(res->Compile(this));
+  return 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";
+CodeGen::Node PolicyCompiler::MaskedEqual(int argno,
+                                          size_t width,
+                                          uint64_t mask,
+                                          uint64_t value,
+                                          CodeGen::Node passed,
+                                          CodeGen::Node failed) {
+  // Sanity check that arguments make sense.
+  CHECK(argno >= 0 && argno < 6) << "Invalid argument number " << argno;
+  CHECK(width == 4 || width == 8) << "Invalid argument width " << width;
+  CHECK_NE(0U, mask) << "Zero mask is invalid";
+  CHECK_EQ(value, value & mask) << "Value contains masked out bits";
   if (sizeof(void*) == 4) {
-    CHECK_EQ(ErrorCode::TP_32BIT, cond.width_)
-        << "Invalid width on 32-bit platform";
+    CHECK_EQ(4U, 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";
+  if (width == 4) {
+    CHECK_EQ(0U, mask >> 32) << "Mask exceeds argument size";
+    CHECK_EQ(0U, 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);
+  return MaskedEqualHalf(argno, width, mask, value, ArgHalf::UPPER,
+                         MaskedEqualHalf(argno, width, mask, value,
+                                         ArgHalf::LOWER, 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) {
+CodeGen::Node PolicyCompiler::MaskedEqualHalf(int argno,
+                                              size_t width,
+                                              uint64_t full_mask,
+                                              uint64_t full_value,
+                                              ArgHalf half,
+                                              CodeGen::Node passed,
+                                              CodeGen::Node failed) {
+  if (width == 4 && half == ArgHalf::UPPER) {
     // Special logic for sanity checking the upper 32-bits of 32-bit system
     // call arguments.
 
     // TODO(mdempsky): Compile Unexpected64bitArgument() just per program.
-    CodeGen::Node invalid_64bit = RetExpression(Unexpected64bitArgument());
+    CodeGen::Node invalid_64bit = Unexpected64bitArgument();
 
-    const uint32_t upper = SECCOMP_ARG_MSB_IDX(cond.argno_);
-    const uint32_t lower = SECCOMP_ARG_LSB_IDX(cond.argno_);
+    const uint32_t upper = SECCOMP_ARG_MSB_IDX(argno);
+    const uint32_t lower = SECCOMP_ARG_LSB_IDX(argno);
 
     if (sizeof(void*) == 4) {
       // On 32-bit platforms, the upper 32-bits should always be 0:
@@ -386,10 +363,11 @@
                 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_;
+  const uint32_t idx = (half == ArgHalf::UPPER) ? SECCOMP_ARG_MSB_IDX(argno)
+                                                : SECCOMP_ARG_LSB_IDX(argno);
+  const uint32_t mask = (half == ArgHalf::UPPER) ? full_mask >> 32 : full_mask;
+  const uint32_t value =
+      (half == ArgHalf::UPPER) ? full_value >> 32 : full_value;
 
   // Emit a suitable instruction sequence for (arg & mask) == value.
 
@@ -444,12 +422,12 @@
               BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed)));
 }
 
-ErrorCode PolicyCompiler::Unexpected64bitArgument() {
-  return Kill("Unexpected 64bit argument detected")->Compile(this);
+CodeGen::Node PolicyCompiler::Unexpected64bitArgument() {
+  return CompileResult(panic_func_("Unexpected 64bit argument detected"));
 }
 
-ErrorCode PolicyCompiler::Error(int err) {
-  if (has_unsafe_traps_) {
+CodeGen::Node PolicyCompiler::Return(uint32_t ret) {
+  if (has_unsafe_traps_ && (ret & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
     // When inside an UnsafeTrap() callback, we want to allow all system calls.
     // This means, we must conditionally disable the sandbox -- and that's not
     // something that kernel-side BPF filters can do, as they cannot inspect
@@ -459,17 +437,18 @@
     // 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 Trap(ReturnErrno, reinterpret_cast<void*>(ret & SECCOMP_RET_DATA),
+                true);
   }
 
-  return ErrorCode(err);
+  return gen_.MakeInstruction(BPF_RET + BPF_K, ret);
 }
 
-ErrorCode PolicyCompiler::Trap(TrapRegistry::TrapFnc fnc,
-                               const void* aux,
-                               bool safe) {
+CodeGen::Node 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);
+  return gen_.MakeInstruction(BPF_RET + BPF_K, SECCOMP_RET_TRAP + trap_id);
 }
 
 bool PolicyCompiler::IsRequiredForUnsafeTrap(int sysno) {
@@ -481,19 +460,5 @@
   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
index df38d4c..6398ef6 100644
--- a/sandbox/linux/bpf_dsl/policy_compiler.h
+++ b/sandbox/linux/bpf_dsl/policy_compiler.h
@@ -7,15 +7,12 @@
 
 #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/linux/bpf_dsl/trap_registry.h"
 #include "sandbox/sandbox_export.h"
 
 namespace sandbox {
@@ -27,60 +24,61 @@
 // Linux kernel.
 class SANDBOX_EXPORT PolicyCompiler {
  public:
+  using PanicFunc = bpf_dsl::ResultExpr (*)(const char* error);
+
   PolicyCompiler(const Policy* policy, TrapRegistry* registry);
   ~PolicyCompiler();
 
   // Compile registers any trap handlers needed by the policy and
   // compiles the policy to a BPF program, which it returns.
-  scoped_ptr<CodeGen::Program> Compile(bool verify);
+  CodeGen::Program Compile();
 
   // 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);
+  // SetPanicFunc sets the callback function used for handling faulty
+  // system call conditions.  The default behavior is to immediately kill
+  // the process.
+  // TODO(mdempsky): Move this into Policy?
+  void SetPanicFunc(PanicFunc panic_func);
 
   // UnsafeTraps require some syscalls to always be allowed.
   // This helper function returns true for these calls.
   static bool IsRequiredForUnsafeTrap(int sysno);
 
-  // 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.
+  // Functions below are meant for use within bpf_dsl itself.
+
+  // Return returns a CodeGen::Node that returns the specified seccomp
+  // return value.
+  CodeGen::Node Return(uint32_t ret);
+
+  // Trap returns a CodeGen::Node to indicate the system call should
+  // instead invoke a trap handler.
+  CodeGen::Node Trap(TrapRegistry::TrapFnc fnc, const void* aux, bool safe);
+
+  // MaskedEqual returns a CodeGen::Node that represents a conditional branch.
   // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared
-  // to "value"; if equal, then "passed" will be returned, otherwise "failed".
-  // If "is32bit" is set, the argument must in the range of 0x0..(1u << 32 - 1)
+  // to "value"; if equal, then "passed" will be executed, otherwise "failed".
+  // If "width" is 4, the argument must in the range of 0x0..(1u << 32 - 1)
   // If it is outside this range, the sandbox treats the system call just
-  // the same as any other ABI violation (i.e. it aborts with an error
-  // message).
-  ErrorCode CondMaskedEqual(int argno,
-                            ErrorCode::ArgType is_32bit,
+  // the same as any other ABI violation (i.e., it panics).
+  CodeGen::Node MaskedEqual(int argno,
+                            size_t width,
                             uint64_t mask,
                             uint64_t value,
-                            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();
+                            CodeGen::Node passed,
+                            CodeGen::Node failed);
 
  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
+  // Used by MaskedEqualHalf to track which half of the argument it's
   // emitting instructions for.
-  enum ArgHalf {
-    LowerHalf,
-    UpperHalf,
+  enum class ArgHalf {
+    LOWER,
+    UPPER,
   };
 
   // Compile the configured policy into a complete instruction sequence.
@@ -109,7 +107,8 @@
 
   // 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
+  // ranges. System calls with identical CodeGen::Nodes are coalesced into a
+  // single
   // range.
   void FindRanges(Ranges* ranges);
 
@@ -122,31 +121,25 @@
   // 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);
+  CodeGen::Node MaskedEqualHalf(int argno,
+                                size_t width,
+                                uint64_t full_mask,
+                                uint64_t full_value,
+                                ArgHalf half,
+                                CodeGen::Node passed,
+                                CodeGen::Node failed);
+
+  // Returns the fatal CodeGen::Node that is used to indicate that somebody
+  // attempted to pass a 64bit value in a 32bit system call argument.
+  CodeGen::Node Unexpected64bitArgument();
 
   const Policy* policy_;
   TrapRegistry* registry_;
   uint64_t escapepc_;
+  PanicFunc panic_func_;
 
-  Conds conds_;
   CodeGen gen_;
   bool has_unsafe_traps_;
 
diff --git a/sandbox/linux/bpf_dsl/seccomp_macros.h b/sandbox/linux/bpf_dsl/seccomp_macros.h
index ca28c1d..af70f21 100644
--- a/sandbox/linux/bpf_dsl/seccomp_macros.h
+++ b/sandbox/linux/bpf_dsl/seccomp_macros.h
@@ -5,12 +5,11 @@
 #ifndef SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
 #define SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
 
-#include <sys/cdefs.h>
+#include <sys/types.h>  // For __BIONIC__.
 // Old Bionic versions do not have sys/user.h.  The if can be removed once we no
 // longer need to support these old Bionic versions.
 // All x86_64 builds use a new enough bionic to have sys/user.h.
 #if !defined(__BIONIC__) || defined(__x86_64__)
-#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
diff --git a/sandbox/linux/bpf_dsl/test_trap_registry.cc b/sandbox/linux/bpf_dsl/test_trap_registry.cc
new file mode 100644
index 0000000..eaf8e34
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/test_trap_registry.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/bpf_dsl/test_trap_registry.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+TestTrapRegistry::TestTrapRegistry() : map_() {}
+TestTrapRegistry::~TestTrapRegistry() {}
+
+uint16_t TestTrapRegistry::Add(TrapFnc fnc, const void* aux, bool safe) {
+  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 TestTrapRegistry::EnableUnsafeTraps() {
+  ADD_FAILURE() << "Unimplemented";
+  return false;
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/test_trap_registry.h b/sandbox/linux/bpf_dsl/test_trap_registry.h
new file mode 100644
index 0000000..161f28e
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/test_trap_registry.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_TEST_TRAP_REGISTRY_H_
+#define SANDBOX_LINUX_BPF_DSL_TEST_TRAP_REGISTRY_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <utility>
+
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+class TestTrapRegistry : public TrapRegistry {
+ public:
+  TestTrapRegistry();
+  virtual ~TestTrapRegistry();
+
+  uint16_t Add(TrapFnc fnc, const void* aux, bool safe) override;
+  bool EnableUnsafeTraps() override;
+
+ private:
+  using Key = std::pair<TrapFnc, const void*>;
+
+  std::map<Key, uint16_t> map_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestTrapRegistry);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_TEST_TRAP_REGISTRY_H_
diff --git a/sandbox/linux/bpf_dsl/test_trap_registry_unittest.cc b/sandbox/linux/bpf_dsl/test_trap_registry_unittest.cc
new file mode 100644
index 0000000..1c08c93
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/test_trap_registry_unittest.cc
@@ -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.
+
+#include "sandbox/linux/bpf_dsl/test_trap_registry.h"
+
+#include <stddef.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+namespace {
+
+intptr_t TestTrapFuncOne(const arch_seccomp_data& data, void* aux) {
+  return 1;
+}
+
+intptr_t TestTrapFuncTwo(const arch_seccomp_data& data, void* aux) {
+  return 2;
+}
+
+// Test that TestTrapRegistry correctly assigns trap IDs to trap handlers.
+TEST(TestTrapRegistry, TrapIDs) {
+  struct {
+    TrapRegistry::TrapFnc fnc;
+    const void* aux;
+  } funcs[] = {
+      {TestTrapFuncOne, nullptr},
+      {TestTrapFuncTwo, nullptr},
+      {TestTrapFuncOne, funcs},
+      {TestTrapFuncTwo, funcs},
+  };
+
+  TestTrapRegistry 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));
+    }
+  }
+}
+
+}  // namespace
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/verifier.cc b/sandbox/linux/bpf_dsl/verifier.cc
index 417c663..fbf0705 100644
--- a/sandbox/linux/bpf_dsl/verifier.cc
+++ b/sandbox/linux/bpf_dsl/verifier.cc
@@ -6,15 +6,8 @@
 
 #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/bpf_dsl/trap_registry.h"
 #include "sandbox/linux/system_headers/linux_filter.h"
 #include "sandbox/linux/system_headers/linux_seccomp.h"
 
@@ -23,9 +16,6 @@
 
 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)
@@ -40,133 +30,6 @@
   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) {
@@ -308,42 +171,6 @@
 
 }  // 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) {
@@ -368,12 +195,12 @@
       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:
+          case SECCOMP_RET_ERRNO:
+          case SECCOMP_RET_KILL:
+          case SECCOMP_RET_TRACE:
+          case SECCOMP_RET_TRAP:
             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";
diff --git a/sandbox/linux/bpf_dsl/verifier.h b/sandbox/linux/bpf_dsl/verifier.h
index b0435d1..9b25ab1 100644
--- a/sandbox/linux/bpf_dsl/verifier.h
+++ b/sandbox/linux/bpf_dsl/verifier.h
@@ -18,23 +18,11 @@
 struct arch_seccomp_data;
 
 namespace bpf_dsl {
-class Policy;
-class PolicyCompiler;
 
+// TODO(mdempsky): This class doesn't perform any verification any more, so it
+// deserves a new name.
 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
diff --git a/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc b/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
index e884774..8e4844f 100644
--- a/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
+++ b/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
@@ -32,12 +32,12 @@
 #include "base/threading/thread.h"
 #include "build/build_config.h"
 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/errorcode.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"
@@ -1267,7 +1267,7 @@
         .Case(9, HasAllBits64(0x300000000ULL))
         .Case(10, HasAllBits64(0x100000001ULL))
 #endif
-        .Default(Kill("Invalid test case number"));
+        .Default(Kill());
   }
   return Allow();
 }
@@ -1453,7 +1453,7 @@
         .Case(9, HasAnyBits64(0x300000000ULL))
         .Case(10, HasAnyBits64(0x100000001ULL))
 #endif
-        .Default(Kill("Invalid test case number"));
+        .Default(Kill());
   }
   return Allow();
 }
@@ -1598,7 +1598,7 @@
         .Case(1, MaskedEqual64(0x00ff00ff00000000, 0x005500aa00000000))
         .Case(2, MaskedEqual64(0x00ff00ff00ff00ff, 0x005500aa005500aa))
 #endif
-        .Default(Kill("Invalid test case number"));
+        .Default(Kill());
   }
 
   return Allow();
diff --git a/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc b/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc
index dafa91d..9d79bff 100644
--- a/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc
+++ b/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc
@@ -73,7 +73,7 @@
 
   std::vector<int> send_fds;
   send_fds.push_back(write_pipe.get());
-  CHECK(UnixDomainSocket::SendMsg(fd, kHello, sizeof(kHello), send_fds));
+  CHECK(base::UnixDomainSocket::SendMsg(fd, kHello, sizeof(kHello), send_fds));
 
   write_pipe.reset();
 
@@ -96,7 +96,7 @@
   // 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(
+  ssize_t n = base::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)));
@@ -112,7 +112,7 @@
   base::ScopedFD recv_sock(fds[0]);
   base::ScopedFD send_sock(fds[1]);
 
-  CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+  CHECK(base::UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
 
   const pid_t pid = fork();
   CHECK_NE(-1, pid);
@@ -142,7 +142,7 @@
   base::ScopedFD recv_sock(fds[0]);
   base::ScopedFD send_sock(fds[1]);
 
-  CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+  CHECK(base::UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
 
   const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
   CHECK_NE(-1, pid);
@@ -176,7 +176,7 @@
   base::ScopedFD recv_sock(fds[0]);
   base::ScopedFD send_sock(fds[1]);
 
-  CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+  CHECK(base::UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
 
   const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
   CHECK_NE(-1, pid);
@@ -242,7 +242,7 @@
   base::ScopedFD send_sock(fds[0]);
   base::ScopedFD recv_sock(fds[1]);
 
-  CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+  CHECK(base::UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
 
   const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
   CHECK_NE(-1, pid);
diff --git a/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc b/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
index 9aa3209..09f2d58 100644
--- a/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
+++ b/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
@@ -2,9 +2,10 @@
 // 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/types.h>
 #include <sys/stat.h>
-#include <fcntl.h>
 #include <unistd.h>
 
 #include <vector>
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi
index e09ba39..f5b3e0f 100644
--- a/sandbox/linux/sandbox_linux.gypi
+++ b/sandbox/linux/sandbox_linux.gypi
@@ -107,22 +107,17 @@
         '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',
+          'variables': {
+            'test_type': 'gtest',
+            'test_suite_name': '<(_target_name)',
+          },
+          'includes': [
+            '../../build/android/test_runner.gypi',
           ],
-        }],
-      ],
+        }]
+      ]
     },
     {
       'target_name': 'seccomp_bpf',
@@ -135,8 +130,7 @@
         'bpf_dsl/codegen.cc',
         'bpf_dsl/codegen.h',
         'bpf_dsl/cons.h',
-        'bpf_dsl/dump_bpf.cc',
-        'bpf_dsl/dump_bpf.h',
+        'bpf_dsl/errorcode.h',
         'bpf_dsl/linux_syscall_ranges.h',
         'bpf_dsl/policy.cc',
         'bpf_dsl/policy.h',
@@ -147,12 +141,8 @@
         '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',
@@ -171,7 +161,7 @@
       'includes': [
         # Disable LTO due to compiler bug
         # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57703
-        '../../build/android/disable_lto.gypi',
+        '../../build/android/disable_gcc_lto.gypi',
       ],
       'include_dirs': [
         '../..',
@@ -297,6 +287,7 @@
         'system_headers/linux_futex.h',
         'system_headers/linux_seccomp.h',
         'system_headers/linux_syscalls.h',
+        'system_headers/linux_time.h',
         'system_headers/linux_ucontext.h',
         'system_headers/mips_linux_syscalls.h',
         'system_headers/mips_linux_ucontext.h',
@@ -308,22 +299,6 @@
       ],
     },
     {
-      # 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': [
@@ -345,6 +320,57 @@
         '..',
       ],
     },
+    {
+      'target_name': 'bpf_dsl_golden',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'generate',
+          'inputs': [
+            'bpf_dsl/golden/generate.py',
+            'bpf_dsl/golden/i386/ArgSizePolicy.txt',
+            'bpf_dsl/golden/i386/BasicPolicy.txt',
+            'bpf_dsl/golden/i386/ElseIfPolicy.txt',
+            'bpf_dsl/golden/i386/MaskingPolicy.txt',
+            'bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt',
+            'bpf_dsl/golden/i386/NegativeConstantsPolicy.txt',
+            'bpf_dsl/golden/i386/SwitchPolicy.txt',
+            'bpf_dsl/golden/x86-64/ArgSizePolicy.txt',
+            'bpf_dsl/golden/x86-64/BasicPolicy.txt',
+            'bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt',
+            'bpf_dsl/golden/x86-64/ElseIfPolicy.txt',
+            'bpf_dsl/golden/x86-64/MaskingPolicy.txt',
+            'bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt',
+            'bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt',
+            'bpf_dsl/golden/x86-64/SwitchPolicy.txt',
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/sandbox/linux/bpf_dsl/golden/golden_files.h',
+          ],
+          'action': [
+            'python',
+            'linux/bpf_dsl/golden/generate.py',
+            '<(SHARED_INTERMEDIATE_DIR)/sandbox/linux/bpf_dsl/golden/golden_files.h',
+            'linux/bpf_dsl/golden/i386/ArgSizePolicy.txt',
+            'linux/bpf_dsl/golden/i386/BasicPolicy.txt',
+            'linux/bpf_dsl/golden/i386/ElseIfPolicy.txt',
+            'linux/bpf_dsl/golden/i386/MaskingPolicy.txt',
+            'linux/bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt',
+            'linux/bpf_dsl/golden/i386/NegativeConstantsPolicy.txt',
+            'linux/bpf_dsl/golden/i386/SwitchPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/ArgSizePolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/BasicPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/ElseIfPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/MaskingPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/SwitchPolicy.txt',
+          ],
+          'message': 'Generating header from golden files ...',
+        },
+      ],
+    },
   ],
   'conditions': [
     [ 'OS=="android"', {
@@ -380,19 +406,26 @@
       }],
     }],
     [ 'OS=="android"', {
-      'targets': [
-        {
-        'target_name': 'sandbox_linux_jni_unittests_apk',
-        'type': 'none',
-        'variables': {
-          'test_suite_name': 'sandbox_linux_jni_unittests',
+      'conditions': [
+        ['test_isolation_mode != "noop"', {
+          'targets': [
+            {
+              'target_name': 'sandbox_linux_unittests_android_run',
+              'type': 'none',
+              'dependencies': [
+                'sandbox_linux_unittests',
+              ],
+              'includes': [
+                '../../build/isolate.gypi',
+              ],
+              'sources': [
+                '../sandbox_linux_unittests_android.isolate',
+              ],
+            },
+          ],
         },
-        'dependencies': [
-          'sandbox_linux_jni_unittests',
-        ],
-        'includes': [ '../../build/apk_test.gypi' ],
-        }
       ],
+    ],
     }],
     ['test_isolation_mode != "noop"', {
       'targets': [
diff --git a/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp b/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp
new file mode 100644
index 0000000..50e637c
--- /dev/null
+++ b/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp
@@ -0,0 +1,87 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    '../../build/common_untrusted.gypi',
+  ],
+  'conditions': [
+    ['disable_nacl==0 and disable_nacl_untrusted==0', {
+      'targets': [
+        {
+          'target_name': 'sandbox_linux_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libsandbox_linux_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+            'compile_flags': [
+              '-fgnu-inline-asm',
+            ],
+            'sources': [
+              # This is the subset of linux build target, needed for
+              # nacl_helper_nonsfi's sandbox implementation.
+              'bpf_dsl/bpf_dsl.cc',
+              'bpf_dsl/codegen.cc',
+              'bpf_dsl/policy.cc',
+              'bpf_dsl/policy_compiler.cc',
+              'bpf_dsl/syscall_set.cc',
+              'seccomp-bpf-helpers/sigsys_handlers.cc',
+              'seccomp-bpf-helpers/syscall_parameters_restrictions.cc',
+              'seccomp-bpf/die.cc',
+              'seccomp-bpf/sandbox_bpf.cc',
+              'seccomp-bpf/syscall.cc',
+              'seccomp-bpf/trap.cc',
+              'services/credentials.cc',
+              'services/namespace_sandbox.cc',
+              'services/namespace_utils.cc',
+              'services/proc_util.cc',
+              'services/resource_limits.cc',
+              'services/syscall_wrappers.cc',
+              'services/thread_helpers.cc',
+              'suid/client/setuid_sandbox_client.cc',
+            ],
+          },
+          'dependencies': [
+            '../../base/base_nacl.gyp:base_nacl_nonsfi',
+          ],
+        },
+      ],
+    }],
+
+    ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
+      'targets': [
+        {
+          'target_name': 'sandbox_linux_test_utils_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libsandbox_linux_test_utils_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+
+            'sources': [
+              'seccomp-bpf/sandbox_bpf_test_runner.cc',
+              'tests/sandbox_test_runner.cc',
+              'tests/unit_tests.cc',
+            ],
+          },
+          'dependencies': [
+            '../../testing/gtest_nacl.gyp:gtest_nacl',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/sandbox/linux/sandbox_linux_test_sources.gypi b/sandbox/linux/sandbox_linux_test_sources.gypi
index 82d7532..612814e 100644
--- a/sandbox/linux/sandbox_linux_test_sources.gypi
+++ b/sandbox/linux/sandbox_linux_test_sources.gypi
@@ -43,17 +43,26 @@
         'bpf_dsl/bpf_dsl_unittest.cc',
         'bpf_dsl/codegen_unittest.cc',
         'bpf_dsl/cons_unittest.cc',
+        'bpf_dsl/dump_bpf.cc',
+        'bpf_dsl/dump_bpf.h',
         'bpf_dsl/syscall_set_unittest.cc',
+        'bpf_dsl/test_trap_registry.cc',
+        'bpf_dsl/test_trap_registry.h',
+        'bpf_dsl/test_trap_registry_unittest.cc',
+        'bpf_dsl/verifier.cc',
+        'bpf_dsl/verifier.h',
         'integration_tests/bpf_dsl_seccomp_unittest.cc',
         'integration_tests/seccomp_broker_process_unittest.cc',
         'seccomp-bpf-helpers/baseline_policy_unittest.cc',
         'seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc',
         'seccomp-bpf/bpf_tests_unittest.cc',
-        'seccomp-bpf/errorcode_unittest.cc',
         'seccomp-bpf/sandbox_bpf_unittest.cc',
         'seccomp-bpf/syscall_unittest.cc',
         'seccomp-bpf/trap_unittest.cc',
       ],
+      'dependencies': [
+        'bpf_dsl_golden',
+      ],
     }],
     [ 'compile_credentials==1', {
       'sources': [
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
index 8c679a3..8bfb025 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -21,6 +21,10 @@
 #include "sandbox/linux/services/syscall_wrappers.h"
 #include "sandbox/linux/system_headers/linux_syscalls.h"
 
+#if !defined(SO_PEEK_OFF)
+#define SO_PEEK_OFF 42
+#endif
+
 // Changing this implementation will have an effect on *all* policies.
 // Currently this means: Renderer/Worker, GPU, Flash and NaCl.
 
@@ -227,6 +231,16 @@
     return RestrictSocketcallCommand();
 #endif
 
+#if defined(__x86_64__)
+  if (sysno == __NR_getsockopt || sysno ==__NR_setsockopt) {
+    // Used by Mojo EDK to catch a message pipe being sent over itself.
+    const Arg<int> level(1);
+    const Arg<int> optname(2);
+    return If(level == SOL_SOCKET && optname == SO_PEEK_OFF,
+              Allow()).Else(CrashSIGSYS());
+  }
+#endif
+
   if (IsBaselinePolicyWatched(sysno)) {
     // Previously unseen syscalls. TODO(jln): some of these should
     // be denied gracefully right away.
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
index 614849f..7ece8be 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <netinet/in.h>
 #include <sched.h>
 #include <signal.h>
 #include <string.h>
@@ -36,6 +37,10 @@
 #include "sandbox/linux/tests/test_utils.h"
 #include "sandbox/linux/tests/unit_tests.h"
 
+#if !defined(SO_PEEK_OFF)
+#define SO_PEEK_OFF 42
+#endif
+
 namespace sandbox {
 
 namespace {
@@ -329,6 +334,51 @@
   clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
 }
 
+#if defined(__x86_64__)
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 GetSockOptWrongLevelSigsys,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int fds[2];
+  PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+  int id;
+  socklen_t peek_off_size = sizeof(id);
+  getsockopt(fds[0], IPPROTO_TCP, SO_PEEK_OFF, &id, &peek_off_size);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 GetSockOptWrongOptionSigsys,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int fds[2];
+  PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+  int id;
+  socklen_t peek_off_size = sizeof(id);
+  getsockopt(fds[0], SOL_SOCKET, SO_DEBUG, &id, &peek_off_size);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 SetSockOptWrongLevelSigsys,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int fds[2];
+  PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+  int id;
+  setsockopt(fds[0], IPPROTO_TCP, SO_PEEK_OFF, &id, sizeof(id));
+}
+
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 SetSockOptWrongOptionSigsys,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int fds[2];
+  PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+  int id;
+  setsockopt(fds[0], SOL_SOCKET, SO_DEBUG, &id, sizeof(id));
+}
+#endif
+
 }  // namespace
 
 }  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
index 60c16d3..9311550 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -22,7 +22,6 @@
 
 #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"
@@ -30,6 +29,7 @@
 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
 #include "sandbox/linux/system_headers/linux_futex.h"
 #include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/system_headers/linux_time.h"
 
 // PNaCl toolchain does not provide sys/ioctl.h header.
 #if !defined(OS_NACL_NONSFI)
@@ -302,13 +302,11 @@
   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_MONOTONIC_COARSE ||
                  clockid == CLOCK_PROCESS_CPUTIME_ID ||
                  clockid == CLOCK_REALTIME ||
+                 clockid == CLOCK_REALTIME_COARSE ||
                  clockid == CLOCK_THREAD_CPUTIME_ID,
              Allow()).Else(CrashSIGSYS());
 }
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
index 0ec396d..b96fe20 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -92,7 +92,6 @@
 // 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.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
index e653b8a..280211a 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
@@ -26,6 +26,7 @@
 #include "sandbox/linux/seccomp-bpf/syscall.h"
 #include "sandbox/linux/services/syscall_wrappers.h"
 #include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/system_headers/linux_time.h"
 #include "sandbox/linux/tests/unit_tests.h"
 
 #if !defined(OS_ANDROID)
@@ -60,7 +61,13 @@
 
 void CheckClock(clockid_t clockid) {
   struct timespec ts;
-  ts.tv_sec = ts.tv_nsec = -1;
+  ts.tv_sec = -1;
+  ts.tv_nsec = -1;
+  BPF_ASSERT_EQ(0, clock_getres(clockid, &ts));
+  BPF_ASSERT_EQ(0, ts.tv_sec);
+  BPF_ASSERT_LE(0, ts.tv_nsec);
+  ts.tv_sec = -1;
+  ts.tv_nsec = -1;
   BPF_ASSERT_EQ(0, clock_gettime(clockid, &ts));
   BPF_ASSERT_LE(0, ts.tv_sec);
   BPF_ASSERT_LE(0, ts.tv_nsec);
@@ -70,8 +77,10 @@
            clock_gettime_allowed,
            RestrictClockIdPolicy) {
   CheckClock(CLOCK_MONOTONIC);
+  CheckClock(CLOCK_MONOTONIC_COARSE);
   CheckClock(CLOCK_PROCESS_CPUTIME_ID);
   CheckClock(CLOCK_REALTIME);
+  CheckClock(CLOCK_REALTIME_COARSE);
   CheckClock(CLOCK_THREAD_CPUTIME_ID);
 }
 
@@ -83,52 +92,6 @@
   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,
diff --git a/sandbox/linux/seccomp-bpf/errorcode.cc b/sandbox/linux/seccomp-bpf/errorcode.cc
deleted file mode 100644
index 9bb3ddb..0000000
--- a/sandbox/linux/seccomp-bpf/errorcode.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. 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
deleted file mode 100644
index d887773..0000000
--- a/sandbox/linux/seccomp-bpf/errorcode.h
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. 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
deleted file mode 100644
index 6b5491e..0000000
--- a/sandbox/linux/seccomp-bpf/errorcode_unittest.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. 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
index 239043e..5fc0990 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -4,12 +4,6 @@
 
 #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>
@@ -22,6 +16,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/third_party/valgrind/valgrind.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
 #include "sandbox/linux/bpf_dsl/codegen.h"
 #include "sandbox/linux/bpf_dsl/policy.h"
 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
@@ -115,6 +110,14 @@
   return static_cast<uint64_t>(static_cast<uintptr_t>(rv));
 }
 
+intptr_t SandboxPanicTrap(const struct arch_seccomp_data&, void* aux) {
+  SANDBOX_DIE(static_cast<const char*>(aux));
+}
+
+bpf_dsl::ResultExpr SandboxPanic(const char* error) {
+  return bpf_dsl::Trap(SandboxPanicTrap, error);
+}
+
 }  // namespace
 
 SandboxBPF::SandboxBPF(bpf_dsl::Policy* policy)
@@ -214,18 +217,15 @@
       static_cast<intptr_t>(args.args[5]));
 }
 
-scoped_ptr<CodeGen::Program> SandboxBPF::AssembleFilter(
-    bool force_verification) {
-#if !defined(NDEBUG)
-  force_verification = true;
-#endif
+CodeGen::Program SandboxBPF::AssembleFilter() {
   DCHECK(policy_);
 
   bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
   if (Trap::SandboxDebuggingAllowedByUser()) {
     compiler.DangerousSetEscapePC(EscapePC());
   }
-  return compiler.Compile(force_verification);
+  compiler.SetPanicFunc(SandboxPanic);
+  return compiler.Compile();
 }
 
 void SandboxBPF::InstallFilter(bool must_sync_threads) {
@@ -240,13 +240,13 @@
   // 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();
+  CodeGen::Program program = AssembleFilter();
 
-  struct sock_filter bpf[program->size()];
-  const struct sock_fprog prog = {static_cast<unsigned short>(program->size()),
+  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;
+  memcpy(bpf, &program[0], sizeof(bpf));
+  CodeGen::Program().swap(program);  // vector swap trick
 
   // Make an attempt to release memory that is no longer needed here, rather
   // than in the destructor. Try to avoid as much as possible to presume of
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/sandbox/linux/seccomp-bpf/sandbox_bpf.h
index 96cceb5..e758e03 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.h
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.h
@@ -91,17 +91,13 @@
   // directly suitable as a return value for a trap handler.
   static intptr_t ForwardSyscall(const struct arch_seccomp_data& args);
 
+ private:
+  friend class SandboxBPFTestRunner;
+
   // Assembles a BPF filter program from the current policy. After calling this
   // function, you must not call any other sandboxing function.
-  // 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);
+  CodeGen::Program AssembleFilter();
 
- private:
   // Assembles and installs a filter based on the policy that has previously
   // been configured with SetSandboxPolicy().
   void InstallFilter(bool must_sync_threads);
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
index 321ea9a..c0193f9 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
@@ -51,7 +51,7 @@
     // 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.AssembleFilter();
     sandbox::UnitTests::IgnoreThisTest();
   }
 }
diff --git a/sandbox/linux/seccomp-bpf/syscall_unittest.cc b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
index 5fdee6c..3fe404c 100644
--- a/sandbox/linux/seccomp-bpf/syscall_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
@@ -5,6 +5,7 @@
 #include "sandbox/linux/seccomp-bpf/syscall.h"
 
 #include <asm/unistd.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/syscall.h>
diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc
index 35bb4dc..dd26472 100644
--- a/sandbox/linux/services/credentials.cc
+++ b/sandbox/linux/services/credentials.cc
@@ -53,7 +53,16 @@
 
 const int kExitSuccess = 0;
 
+#if defined(__clang__)
+// Disable sanitizers that rely on TLS and may write to non-stack memory.
+__attribute__((no_sanitize_address))
+__attribute__((no_sanitize_thread))
+__attribute__((no_sanitize_memory))
+#endif
 int ChrootToSelfFdinfo(void*) {
+  // This function can be run from a vforked child, so it should not write to
+  // any memory other than the stack or errno. Reads from TLS may be different
+  // from in the parent process.
   RAW_CHECK(sys_chroot("/proc/self/fdinfo/") == 0);
 
   // CWD is essentially an implicit file descriptor, so be careful to not
@@ -91,9 +100,22 @@
 #error "Unsupported architecture"
 #endif
 
-  pid = clone(ChrootToSelfFdinfo, stack,
-              CLONE_VM | CLONE_VFORK | CLONE_FS | LINUX_SIGCHLD, nullptr,
-              nullptr, nullptr, nullptr);
+  int clone_flags = CLONE_FS | LINUX_SIGCHLD;
+  void* tls = nullptr;
+#if defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARM_FAMILY)
+  // Use CLONE_VM | CLONE_VFORK as an optimization to avoid copying page tables.
+  // Since clone writes to the new child's TLS before returning, we must set a
+  // new TLS to avoid corrupting the current process's TLS. On ARCH_CPU_X86,
+  // glibc performs syscalls by calling a function pointer in TLS, so we do not
+  // attempt this optimization.
+  clone_flags |= CLONE_VM | CLONE_VFORK | CLONE_SETTLS;
+
+  char tls_buf[PTHREAD_STACK_MIN] = {0};
+  tls = tls_buf;
+#endif
+
+  pid = clone(ChrootToSelfFdinfo, stack, clone_flags, nullptr, nullptr, tls,
+              nullptr);
   PCHECK(pid != -1);
 
   int status = -1;
@@ -296,4 +318,15 @@
   return true;
 }
 
+pid_t Credentials::ForkAndDropCapabilitiesInChild() {
+  pid_t pid = fork();
+  if (pid != 0) {
+    return pid;
+  }
+
+  // Since we just forked, we are single threaded.
+  PCHECK(DropAllCapabilitiesOnCurrentThread());
+  return 0;
+}
+
 }  // namespace sandbox.
diff --git a/sandbox/linux/services/credentials.h b/sandbox/linux/services/credentials.h
index 0001dc7..095d636 100644
--- a/sandbox/linux/services/credentials.h
+++ b/sandbox/linux/services/credentials.h
@@ -95,6 +95,9 @@
   //   - DropAllCapabilities() must be called to prevent escapes.
   static bool DropFileSystemAccess(int proc_fd) WARN_UNUSED_RESULT;
 
+  // Forks and drops capabilities in the child.
+  static pid_t ForkAndDropCapabilitiesInChild();
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Credentials);
 };
diff --git a/sandbox/linux/services/credentials_unittest.cc b/sandbox/linux/services/credentials_unittest.cc
index 6b93c86..39fd6a7 100644
--- a/sandbox/linux/services/credentials_unittest.cc
+++ b/sandbox/linux/services/credentials_unittest.cc
@@ -6,6 +6,8 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
 #include <stdio.h>
 #include <sys/capability.h>
 #include <sys/stat.h>
@@ -237,6 +239,31 @@
   CHECK_EQ(0, cap_compare(expected_cap.get(), actual_cap.get()));
 }
 
+volatile sig_atomic_t signal_handler_called;
+void SignalHandler(int sig) {
+  signal_handler_called = 1;
+}
+
+// Disabled on ASAN because of crbug.com/451603.
+SANDBOX_TEST(Credentials, DISABLE_ON_ASAN(DropFileSystemAccessPreservesTLS)) {
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  CHECK(Credentials::DropFileSystemAccess(ProcUtil::OpenProc().get()));
+
+  // In glibc, pthread_getattr_np makes an assertion about the cached PID/TID in
+  // TLS.
+  pthread_attr_t attr;
+  EXPECT_EQ(0, pthread_getattr_np(pthread_self(), &attr));
+
+  // raise also uses the cached TID in glibc.
+  struct sigaction action = {};
+  action.sa_handler = &SignalHandler;
+  PCHECK(sigaction(SIGUSR1, &action, nullptr) == 0);
+
+  PCHECK(raise(SIGUSR1) == 0);
+  CHECK_EQ(1, signal_handler_called);
+}
+
 }  // namespace.
 
 }  // namespace sandbox.
diff --git a/sandbox/linux/services/init_process_reaper.cc b/sandbox/linux/services/init_process_reaper.cc
index 2e0b90b..2ff18b5 100644
--- a/sandbox/linux/services/init_process_reaper.cc
+++ b/sandbox/linux/services/init_process_reaper.cc
@@ -74,7 +74,7 @@
         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
+        // Exit with the same exit code as our child. Exit with 0 if we got
         // signaled.
         _exit(exit_code);
       }
diff --git a/sandbox/linux/services/libc_urandom_override.cc b/sandbox/linux/services/libc_urandom_override.cc
deleted file mode 100644
index 33bb25d..0000000
--- a/sandbox/linux/services/libc_urandom_override.cc
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. 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
deleted file mode 100644
index 86212f8..0000000
--- a/sandbox/linux/services/libc_urandom_override.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. 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
index 2379644..a82caf4 100644
--- a/sandbox/linux/services/namespace_sandbox.cc
+++ b/sandbox/linux/services/namespace_sandbox.cc
@@ -24,6 +24,8 @@
 #include "base/process/process.h"
 #include "sandbox/linux/services/credentials.h"
 #include "sandbox/linux/services/namespace_utils.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
 
 namespace sandbox {
 
@@ -65,6 +67,7 @@
   // An empty string causes the env var to be unset in the child process.
   (*environ)[env_var] = value ? "1" : "";
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 // Linux supports up to 64 signals. This should be updated if that ever changes.
 int g_signal_exit_codes[64];
@@ -77,42 +80,70 @@
     _exit(g_signal_exit_codes[sig_idx]);
   }
 
-  _exit(NamespaceSandbox::kDefaultExitCode);
+  _exit(NamespaceSandbox::SignalExitCode(sig));
 }
-#endif  // !defined(OS_NACL_NONSFI)
 
 }  // namespace
 
 #if !defined(OS_NACL_NONSFI)
+NamespaceSandbox::Options::Options()
+    : ns_types(CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET),
+      fail_on_unsupported_ns_type(false) {}
+
+NamespaceSandbox::Options::~Options() {}
+
 // static
 base::Process NamespaceSandbox::LaunchProcess(
     const base::CommandLine& cmdline,
-    const base::LaunchOptions& options) {
-  return LaunchProcess(cmdline.argv(), options);
+    const base::LaunchOptions& launch_options) {
+  return LaunchProcessWithOptions(cmdline.argv(), launch_options, Options());
 }
 
 // static
 base::Process NamespaceSandbox::LaunchProcess(
     const std::vector<std::string>& argv,
-    const base::LaunchOptions& options) {
+    const base::LaunchOptions& launch_options) {
+  return LaunchProcessWithOptions(argv, launch_options, Options());
+}
+
+// static
+base::Process NamespaceSandbox::LaunchProcessWithOptions(
+    const base::CommandLine& cmdline,
+    const base::LaunchOptions& launch_options,
+    const Options& ns_sandbox_options) {
+  return LaunchProcessWithOptions(cmdline.argv(), launch_options,
+                                  ns_sandbox_options);
+}
+
+// static
+base::Process NamespaceSandbox::LaunchProcessWithOptions(
+    const std::vector<std::string>& argv,
+    const base::LaunchOptions& launch_options,
+    const Options& ns_sandbox_options) {
+  // These fields may not be set by the caller.
+  CHECK(launch_options.pre_exec_delegate == nullptr);
+  CHECK_EQ(0, launch_options.clone_flags);
+
   int clone_flags = 0;
-  int ns_types[] = {CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET};
-  for (const int ns_type : ns_types) {
+  const int kSupportedTypes[] = {CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET};
+  for (const int ns_type : kSupportedTypes) {
+    if ((ns_type & ns_sandbox_options.ns_types) == 0) {
+      continue;
+    }
+
     if (NamespaceUtils::KernelSupportsUnprivilegedNamespace(ns_type)) {
       clone_flags |= ns_type;
+    } else if (ns_sandbox_options.fail_on_unsupported_ns_type) {
+      return base::Process();
     }
   }
   CHECK(clone_flags & CLONE_NEWUSER);
 
-  // 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;
+  base::LaunchOptions launch_options_copy = launch_options;
+  launch_options_copy.pre_exec_delegate = &write_uid_gid_map_delegate;
+  launch_options_copy.clone_flags = clone_flags;
 
   const std::pair<int, const char*> clone_flag_environ[] = {
       std::make_pair(CLONE_NEWUSER, kSandboxUSERNSEnvironmentVarName),
@@ -120,20 +151,21 @@
       std::make_pair(CLONE_NEWNET, kSandboxNETNSEnvironmentVarName),
   };
 
-  base::EnvironmentMap* environ = &launch_options.environ;
+  base::EnvironmentMap* environ = &launch_options_copy.environ;
   for (const auto& entry : clone_flag_environ) {
     const int flag = entry.first;
     const char* environ_name = entry.second;
     SetEnvironForNamespaceType(environ, environ_name, clone_flags & flag);
   }
 
-  return base::LaunchProcess(argv, launch_options);
+  return base::LaunchProcess(argv, launch_options_copy);
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 // static
 pid_t NamespaceSandbox::ForkInNewPidNamespace(bool drop_capabilities_in_child) {
   const pid_t pid =
-      base::ForkWithFlags(CLONE_NEWPID | SIGCHLD, nullptr, nullptr);
+      base::ForkWithFlags(CLONE_NEWPID | LINUX_SIGCHLD, nullptr, nullptr);
   if (pid < 0) {
     return pid;
   }
@@ -153,11 +185,12 @@
 // static
 void NamespaceSandbox::InstallDefaultTerminationSignalHandlers() {
   static const int kDefaultTermSignals[] = {
-      SIGHUP, SIGINT, SIGABRT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2,
+      LINUX_SIGHUP,  LINUX_SIGINT,  LINUX_SIGABRT, LINUX_SIGQUIT,
+      LINUX_SIGPIPE, LINUX_SIGTERM, LINUX_SIGUSR1, LINUX_SIGUSR2,
   };
 
   for (const int sig : kDefaultTermSignals) {
-    InstallTerminationSignalHandler(sig, kDefaultExitCode);
+    InstallTerminationSignalHandler(sig, SignalExitCode(sig));
   }
 }
 
@@ -166,12 +199,16 @@
     int sig,
     int exit_code) {
   struct sigaction old_action;
-  PCHECK(sigaction(sig, nullptr, &old_action) == 0);
+  PCHECK(sys_sigaction(sig, nullptr, &old_action) == 0);
 
+#if !defined(OS_NACL_NONSFI)
   if (old_action.sa_flags & SA_SIGINFO &&
       old_action.sa_sigaction != nullptr) {
     return false;
-  } else if (old_action.sa_handler != SIG_DFL) {
+  }
+#endif
+
+  if (old_action.sa_handler != LINUX_SIG_DFL) {
     return false;
   }
 
@@ -185,10 +222,9 @@
 
   struct sigaction action = {};
   action.sa_handler = &TerminationSignalHandler;
-  PCHECK(sigaction(sig, &action, nullptr) == 0);
+  PCHECK(sys_sigaction(sig, &action, nullptr) == 0);
   return true;
 }
-#endif  // !defined(OS_NACL_NONSFI)
 
 // static
 bool NamespaceSandbox::InNewUserNamespace() {
diff --git a/sandbox/linux/services/namespace_sandbox.h b/sandbox/linux/services/namespace_sandbox.h
index 80097fb..b5832fb 100644
--- a/sandbox/linux/services/namespace_sandbox.h
+++ b/sandbox/linux/services/namespace_sandbox.h
@@ -38,7 +38,17 @@
 class SANDBOX_EXPORT NamespaceSandbox {
  public:
 #if !defined(OS_NACL_NONSFI)
-  static const int kDefaultExitCode = 1;
+  struct Options {
+    Options();
+    ~Options();
+
+    // Bitmask of namespace types. Must be some combination of CLONE_NEWUSER
+    // (required), CLONE_NEWPID, and CLONE_NEWNET. Defaults to all of the above.
+    int ns_types;
+
+    // Fail if any of the namespace types are not supported. Defaults to false.
+    bool fail_on_unsupported_ns_type;
+  };
 
   // Launch a new process inside its own user/PID/network namespaces (depending
   // on kernel support). Requires at a minimum that user namespaces are
@@ -48,9 +58,21 @@
   // 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);
+                                     const base::LaunchOptions& launch_options);
   static base::Process LaunchProcess(const std::vector<std::string>& argv,
-                                     const base::LaunchOptions& options);
+                                     const base::LaunchOptions& launch_options);
+
+  // Versions which take namespace sandbox options. These allow fine grained
+  // control over the types of namespaces used.
+  static base::Process LaunchProcessWithOptions(
+      const base::CommandLine& cmdline,
+      const base::LaunchOptions& launch_options,
+      const Options& ns_sandbox_options);
+  static base::Process LaunchProcessWithOptions(
+      const std::vector<std::string>& argv,
+      const base::LaunchOptions& launch_options,
+      const Options& ns_sandbox_options);
+#endif  // !defined(OS_NACL_NONSFI)
 
   // Forks a process in its own PID namespace. The child process is the init
   // process inside of the PID namespace, so if the child needs to fork further,
@@ -70,8 +92,8 @@
   //
   // 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
+  // that exits with SignalExitCode(sig). These are signals whose default action
+  // is to terminate the program (apart from SIGILL, SIGFPE, and SIGSEGV, which
   // will still terminate the process if e.g. an illegal instruction is
   // encountered, etc.).
   //
@@ -83,7 +105,10 @@
   // 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 an exit code corresponding to the process being killed by sig. This
+  // is the same as exit code that NaCl's default signal handler uses.
+  static int SignalExitCode(int sig) { return -sig & 0xff; }
 
   // Returns whether the namespace sandbox created a new user, PID, and network
   // namespace. In particular, InNewUserNamespace should return true iff the
diff --git a/sandbox/linux/services/namespace_sandbox_unittest.cc b/sandbox/linux/services/namespace_sandbox_unittest.cc
index 547ef67..43e0ae5 100644
--- a/sandbox/linux/services/namespace_sandbox_unittest.cc
+++ b/sandbox/linux/services/namespace_sandbox_unittest.cc
@@ -42,6 +42,12 @@
 class NamespaceSandboxTest : public base::MultiProcessTest {
  public:
   void TestProc(const std::string& procname) {
+    TestProcWithOptions(procname, NamespaceSandbox::Options());
+  }
+
+  void TestProcWithOptions(
+      const std::string& procname,
+      const NamespaceSandbox::Options& ns_sandbox_options) {
     if (!Credentials::CanCreateProcessInNewUserNS()) {
       return;
     }
@@ -53,8 +59,8 @@
     base::LaunchOptions launch_options;
     launch_options.fds_to_remap = &fds_to_remap;
 
-    base::Process process =
-        NamespaceSandbox::LaunchProcess(MakeCmdLine(procname), launch_options);
+    base::Process process = NamespaceSandbox::LaunchProcessWithOptions(
+        MakeCmdLine(procname), launch_options, ns_sandbox_options);
     ASSERT_TRUE(process.IsValid());
 
     const int kDummyExitCode = 42;
@@ -65,10 +71,9 @@
 };
 
 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();
+  const bool in_user_ns = NamespaceSandbox::InNewUserNamespace();
+  const bool in_pid_ns = NamespaceSandbox::InNewPidNamespace();
+  const bool in_net_ns = NamespaceSandbox::InNewNetNamespace();
   CHECK(in_user_ns);
   CHECK_EQ(in_pid_ns,
            NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWPID));
@@ -84,6 +89,27 @@
   TestProc("SimpleChildProcess");
 }
 
+MULTIPROCESS_TEST_MAIN(PidNsOnlyChildProcess) {
+  const bool in_user_ns = NamespaceSandbox::InNewUserNamespace();
+  const bool in_pid_ns = NamespaceSandbox::InNewPidNamespace();
+  const bool in_net_ns = NamespaceSandbox::InNewNetNamespace();
+  CHECK(in_user_ns);
+  CHECK_EQ(in_pid_ns,
+           NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWPID));
+  CHECK(!in_net_ns);
+  if (in_pid_ns) {
+    CHECK_EQ(1, getpid());
+  }
+  return 0;
+}
+
+
+TEST_F(NamespaceSandboxTest, BasicUsageWithOptions) {
+  NamespaceSandbox::Options options;
+  options.ns_types = CLONE_NEWUSER | CLONE_NEWPID;
+  TestProcWithOptions("PidNsOnlyChildProcess", options);
+}
+
 MULTIPROCESS_TEST_MAIN(ChrootMe) {
   CHECK(!RootDirectoryIsEmpty());
   CHECK(sandbox::Credentials::MoveToNewUserNS());
@@ -120,7 +146,6 @@
 }
 
 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.
@@ -182,7 +207,7 @@
     CHECK_EQ(1, getpid());
     CHECK(!Credentials::HasAnyCapability());
     CHECK(NamespaceSandbox::InstallTerminationSignalHandler(
-        SIGTERM, kSignalTerminationExitCode));
+        SIGTERM, NamespaceSandbox::SignalExitCode(SIGTERM)));
     while (true) {
       raise(SIGTERM);
     }
@@ -191,7 +216,7 @@
   int status;
   PCHECK(waitpid(pid, &status, 0) == pid);
   CHECK(WIFEXITED(status));
-  CHECK_EQ(kSignalTerminationExitCode, WEXITSTATUS(status));
+  CHECK_EQ(NamespaceSandbox::SignalExitCode(SIGTERM), WEXITSTATUS(status));
 }
 
 volatile sig_atomic_t signal_handler_called;
@@ -206,7 +231,7 @@
 
   NamespaceSandbox::InstallDefaultTerminationSignalHandlers();
   CHECK(!NamespaceSandbox::InstallTerminationSignalHandler(
-            SIGUSR1, kSignalTerminationExitCode));
+            SIGUSR1, NamespaceSandbox::SignalExitCode(SIGUSR1)));
 
   raise(SIGUSR1);
   CHECK_EQ(1, signal_handler_called);
diff --git a/sandbox/linux/services/namespace_utils.h b/sandbox/linux/services/namespace_utils.h
index f3c88a9..7231033 100644
--- a/sandbox/linux/services/namespace_utils.h
+++ b/sandbox/linux/services/namespace_utils.h
@@ -17,7 +17,8 @@
 // Utility functions for using Linux namepaces.
 class SANDBOX_EXPORT NamespaceUtils {
  public:
-  COMPILE_ASSERT((base::is_same<uid_t, gid_t>::value), UidAndGidAreSameType);
+  static_assert((base::is_same<uid_t, gid_t>::value),
+                "uid_t and gid_t must be the same type");
   // generic_id_t can be used for either uid_t or gid_t.
   typedef uid_t generic_id_t;
 
diff --git a/sandbox/linux/services/proc_util.cc b/sandbox/linux/services/proc_util.cc
index d3f755f..8341b4a 100644
--- a/sandbox/linux/services/proc_util.cc
+++ b/sandbox/linux/services/proc_util.cc
@@ -111,7 +111,7 @@
   return HasOpenDirectory(proc_fd.get());
 }
 
-//static
+// static
 base::ScopedFD ProcUtil::OpenProc() {
   return OpenDirectory("/proc/");
 }
diff --git a/sandbox/linux/services/scoped_process_unittest.cc b/sandbox/linux/services/scoped_process_unittest.cc
index 8bd2847..86f97a8 100644
--- a/sandbox/linux/services/scoped_process_unittest.cc
+++ b/sandbox/linux/services/scoped_process_unittest.cc
@@ -12,6 +12,7 @@
 #include <unistd.h>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
@@ -35,8 +36,6 @@
   _exit(0);
 }
 
-void DoNothing() {}
-
 TEST(ScopedProcess, ScopedProcessNormalExit) {
   const int kCustomExitCode = 12;
   ScopedProcess process(base::Bind(&ExitWithCode, kCustomExitCode));
@@ -64,7 +63,7 @@
 }
 
 TEST(ScopedProcess, ScopedProcessSignaled) {
-  ScopedProcess process(base::Bind(&DoNothing));
+  ScopedProcess process(base::Bind(&base::DoNothing));
   bool got_signaled = false;
   ASSERT_EQ(0, kill(process.GetPid(), SIGKILL));
   int exit_code = process.WaitForExit(&got_signaled);
@@ -92,7 +91,7 @@
 }
 
 TEST(ScopedProcess, SynchronizationBasic) {
-  ScopedProcess process1(base::Bind(&DoNothing));
+  ScopedProcess process1(base::Bind(&base::DoNothing));
   EXPECT_TRUE(process1.WaitForClosureToRun());
 
   ScopedProcess process2(base::Bind(&DoExit));
diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc
index 264eb68..9d5a6ad 100644
--- a/sandbox/linux/services/syscall_wrappers.cc
+++ b/sandbox/linux/services/syscall_wrappers.cc
@@ -33,10 +33,10 @@
 }
 
 long sys_clone(unsigned long flags,
-               decltype(nullptr) child_stack,
+               std::nullptr_t child_stack,
                pid_t* ptid,
                pid_t* ctid,
-               decltype(nullptr) tls) {
+               std::nullptr_t tls) {
   const bool clone_tls_used = flags & CLONE_SETTLS;
   const bool invalid_ctid =
       (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid;
@@ -139,104 +139,119 @@
   return syscall(__NR_unshare, flags);
 }
 
-int sys_sigprocmask(int how, const sigset_t* set, decltype(nullptr) oldset) {
+int sys_sigprocmask(int how, const sigset_t* set, std::nullptr_t oldset) {
   // In some toolchain (in particular Android and PNaCl toolchain),
-  // sigset_t is 32 bits, but Linux ABI requires 64 bits.
-  uint64_t linux_value = 0;
-  std::memcpy(&linux_value, set, std::min(sizeof(sigset_t), sizeof(uint64_t)));
+  // sigset_t is 32 bits, but the Linux ABI uses more.
+  LinuxSigSet linux_value;
+  std::memset(&linux_value, 0, sizeof(LinuxSigSet));
+  std::memcpy(&linux_value, set, std::min(sizeof(sigset_t),
+                                          sizeof(LinuxSigSet)));
+
   return syscall(__NR_rt_sigprocmask, how, &linux_value, nullptr,
                  sizeof(linux_value));
 }
 
-#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.
+// Linux's ABI.
+#if !defined(OS_NACL_NONSFI)
 int sys_sigaction(int signum,
                   const struct sigaction* act,
                   struct sigaction* oldact) {
   return sigaction(signum, act, oldact);
 }
 #else
-// 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;
-};
+#if defined(ARCH_CPU_X86_FAMILY)
 
-// On X86_64 arch, it is necessary to set sa_restorer always.
-#if defined(ARCH_CPU_X86_64)
+// On x86_64, sa_restorer is required. We specify it on x86 as well in order to
+// support kernels with VDSO disabled.
 #if !defined(SA_RESTORER)
 #define SA_RESTORER 0x04000000
 #endif
 
+// XSTR(__NR_foo) expands to a string literal containing the value value of
+// __NR_foo.
+#define STR(x) #x
+#define XSTR(x) STR(x)
+
 // rt_sigreturn is a special system call that interacts with the user land
 // stack. Thus, here prologue must not be created, which implies syscall()
-// does not work properly, too. Note that rt_sigreturn will never return.
-static __attribute__((naked)) void sys_rt_sigreturn() {
-  // Just invoke rt_sigreturn system call.
-  asm volatile ("syscall\n"
-                :: "a"(__NR_rt_sigreturn));
+// does not work properly, too. Note that rt_sigreturn does not return.
+// TODO(rickyz): These assembly functions may still break stack unwinding on
+// nonsfi NaCl builds.
+#if defined(ARCH_CPU_X86_64)
+
+extern "C" {
+  void sys_rt_sigreturn();
 }
+
+asm(
+    ".text\n"
+    "sys_rt_sigreturn:\n"
+    "mov $" XSTR(__NR_rt_sigreturn) ", %eax\n"
+    "syscall\n");
+
+#elif defined(ARCH_CPU_X86)
+extern "C" {
+  void sys_sigreturn();
+  void sys_rt_sigreturn();
+}
+
+asm(
+    ".text\n"
+    "sys_rt_sigreturn:\n"
+    "mov $" XSTR(__NR_rt_sigreturn) ", %eax\n"
+    "int $0x80\n"
+
+    "sys_sigreturn:\n"
+    "pop %eax\n"
+    "mov $" XSTR(__NR_sigreturn) ", %eax\n"
+    "int $0x80\n");
+#else
+#error "Unsupported architecture."
+#endif
+
+#undef STR
+#undef XSTR
+
 #endif
 
 int sys_sigaction(int signum,
                   const struct sigaction* act,
                   struct sigaction* oldact) {
-  KernelSigAction kernel_act = {};
+  LinuxSigAction linux_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;
+    linux_act.kernel_handler = act->sa_handler;
+    std::memcpy(&linux_act.sa_mask, &act->sa_mask,
+                std::min(sizeof(linux_act.sa_mask), sizeof(act->sa_mask)));
+    linux_act.sa_flags = act->sa_flags;
 
+#if defined(ARCH_CPU_X86_FAMILY)
+    if (!(linux_act.sa_flags & SA_RESTORER)) {
+      linux_act.sa_flags |= SA_RESTORER;
 #if defined(ARCH_CPU_X86_64)
-    if (!(kernel_act.sa_flags & SA_RESTORER)) {
-      kernel_act.sa_flags |= SA_RESTORER;
-      kernel_act.sa_restorer = sys_rt_sigreturn;
+      linux_act.sa_restorer = sys_rt_sigreturn;
+#elif defined(ARCH_CPU_X86)
+      linux_act.sa_restorer =
+          linux_act.sa_flags & SA_SIGINFO ? sys_rt_sigreturn : sys_sigreturn;
+#else
+#error "Unsupported architecture."
+#endif
     }
 #endif
   }
 
-  KernelSigAction kernel_oldact = {};
-  int result = syscall(__NR_rt_sigaction, signum, act ? &kernel_act : nullptr,
-                       oldact ? &kernel_oldact : nullptr, sizeof(uint64_t));
+  LinuxSigAction linux_oldact = {};
+  int result = syscall(__NR_rt_sigaction, signum, act ? &linux_act : nullptr,
+                       oldact ? &linux_oldact : nullptr,
+                       sizeof(LinuxSigSet));
+
   if (result == 0 && oldact) {
-    oldact->sa_handler = kernel_oldact.kernel_handler;
+    oldact->sa_handler = linux_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;
+    std::memcpy(&oldact->sa_mask, &linux_oldact.sa_mask,
+                std::min(sizeof(linux_act.sa_mask), sizeof(act->sa_mask)));
+    oldact->sa_flags = linux_oldact.sa_flags;
   }
   return result;
 }
diff --git a/sandbox/linux/services/syscall_wrappers.h b/sandbox/linux/services/syscall_wrappers.h
index 581425a..057e4c8 100644
--- a/sandbox/linux/services/syscall_wrappers.h
+++ b/sandbox/linux/services/syscall_wrappers.h
@@ -9,6 +9,8 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <cstddef>
+
 #include "sandbox/sandbox_export.h"
 
 struct sock_fprog;
@@ -32,10 +34,10 @@
 // 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,
+                              std::nullptr_t child_stack,
                               pid_t* ptid,
                               pid_t* ctid,
-                              decltype(nullptr) regs);
+                              std::nullptr_t regs);
 
 SANDBOX_EXPORT void sys_exit_group(int status);
 
@@ -71,7 +73,7 @@
 // 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);
+                                   std::nullptr_t oldset);
 
 // Some libcs do not expose a sigaction().
 SANDBOX_EXPORT int sys_sigaction(int signum,
diff --git a/sandbox/linux/services/thread_helpers.cc b/sandbox/linux/services/thread_helpers.cc
index 80766a9..20752c8 100644
--- a/sandbox/linux/services/thread_helpers.cc
+++ b/sandbox/linux/services/thread_helpers.cc
@@ -29,6 +29,10 @@
 
 const char kAssertSingleThreadedError[] =
     "Current process is not mono-threaded!";
+const char kAssertThreadDoesNotAppearInProcFS[] =
+    "Started thread does not appear in /proc";
+const char kAssertThreadDoesNotDisappearInProcFS[] =
+    "Stopped thread does not disappear in /proc";
 
 bool IsSingleThreadedImpl(int proc_fd) {
   CHECK_LE(0, proc_fd);
@@ -56,13 +60,18 @@
   return true;
 }
 
+bool IsNotThreadPresentInProcFS(int proc_fd,
+                                const std::string& thread_id_dir_str) {
+  return !IsThreadPresentInProcFS(proc_fd, thread_id_dir_str);
+}
+
 // Run |cb| in a loop until it returns false. Every time |cb| runs, sleep
 // for an exponentially increasing amount of time. |cb| is expected to return
 // false very quickly and this will crash if it doesn't happen within ~64ms on
 // Debug builds (2s on Release builds).
 // This is guaranteed to not sleep more than twice as much as the bare minimum
 // amount of time.
-void RunWhileTrue(const base::Callback<bool(void)>& cb) {
+void RunWhileTrue(const base::Callback<bool(void)>& cb, const char* message) {
 #if defined(NDEBUG)
   // In Release mode, crash after 30 iterations, which means having spent
   // roughly 2s in
@@ -91,8 +100,7 @@
     PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts)));
   }
 
-  LOG(FATAL) << kAssertSingleThreadedError << " (iterations: " << kMaxIterations
-             << ")";
+  LOG(FATAL) << message << " (iterations: " << kMaxIterations << ")";
 
   NOTREACHED();
 }
@@ -101,6 +109,51 @@
   return !ThreadHelpers::IsSingleThreaded(proc_fd);
 }
 
+enum class ThreadAction { Start, Stop };
+
+bool ChangeThreadStateAndWatchProcFS(
+    int proc_fd, base::Thread* thread, ThreadAction action) {
+  DCHECK_LE(0, proc_fd);
+  DCHECK(thread);
+  DCHECK(action == ThreadAction::Start || action == ThreadAction::Stop);
+
+  base::Callback<bool(void)> cb;
+  const char* message;
+
+  if (action == ThreadAction::Start) {
+    // Should start the thread before calling thread_id().
+    if (!thread->Start())
+      return false;
+  }
+
+  const base::PlatformThreadId thread_id = thread->GetThreadId();
+  const std::string thread_id_dir_str =
+      "self/task/" + base::IntToString(thread_id) + "/";
+
+  if (action == ThreadAction::Stop) {
+    // The target thread should exist in /proc.
+    DCHECK(IsThreadPresentInProcFS(proc_fd, thread_id_dir_str));
+    thread->Stop();
+  }
+
+  // The kernel is at liberty to wake the thread id futex before updating
+  // /proc. Start() above or following Stop(), the thread is started or joined,
+  // but entries in /proc may not have been updated.
+  if (action == ThreadAction::Start) {
+    cb = base::Bind(&IsNotThreadPresentInProcFS, proc_fd, thread_id_dir_str);
+    message = kAssertThreadDoesNotAppearInProcFS;
+  } else {
+    cb = base::Bind(&IsThreadPresentInProcFS, proc_fd, thread_id_dir_str);
+    message = kAssertThreadDoesNotDisappearInProcFS;
+  }
+  RunWhileTrue(cb, message);
+
+  DCHECK_EQ(action == ThreadAction::Start,
+            IsThreadPresentInProcFS(proc_fd, thread_id_dir_str));
+
+  return true;
+}
+
 }  // namespace
 
 // static
@@ -119,7 +172,7 @@
 void ThreadHelpers::AssertSingleThreaded(int proc_fd) {
   DCHECK_LE(0, proc_fd);
   const base::Callback<bool(void)> cb = base::Bind(&IsMultiThreaded, proc_fd);
-  RunWhileTrue(cb);
+  RunWhileTrue(cb, kAssertSingleThreadedError);
 }
 
 void ThreadHelpers::AssertSingleThreaded() {
@@ -128,25 +181,15 @@
 }
 
 // static
+bool ThreadHelpers::StartThreadAndWatchProcFS(int proc_fd,
+                                              base::Thread* thread) {
+  return ChangeThreadStateAndWatchProcFS(proc_fd, thread, ThreadAction::Start);
+}
+
+// static
 bool ThreadHelpers::StopThreadAndWatchProcFS(int proc_fd,
                                              base::Thread* thread) {
-  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;
+  return ChangeThreadStateAndWatchProcFS(proc_fd, thread, ThreadAction::Stop);
 }
 
 // static
diff --git a/sandbox/linux/services/thread_helpers.h b/sandbox/linux/services/thread_helpers.h
index f4abdff..73e041a 100644
--- a/sandbox/linux/services/thread_helpers.h
+++ b/sandbox/linux/services/thread_helpers.h
@@ -14,20 +14,24 @@
 
 class SANDBOX_EXPORT ThreadHelpers {
  public:
-  // Check whether the current process is single threaded. |proc_fd|
+  // Checks whether the current process is single threaded. |proc_fd|
   // must be a file descriptor to /proc/ and remains owned by the
   // caller.
   static bool IsSingleThreaded(int proc_fd);
   static bool IsSingleThreaded();
 
-  // Crash if the current process is not single threaded. This will wait
+  // Crashes if the current process is not single threaded. This will wait
   // on /proc to be updated. In the case where this doesn't crash, this will
   // return promptly. In the case where this does crash, this will first wait
   // for a few ms in Debug mode, a few seconds in Release mode.
   static void AssertSingleThreaded(int proc_fd);
   static void AssertSingleThreaded();
 
-  // Stop |thread| and ensure that it does not have an entry in
+  // Starts |thread| and ensure that it has an entry in /proc/self/task/ from
+  // the point of view of the current thread.
+  static bool StartThreadAndWatchProcFS(int proc_fd, base::Thread* thread);
+
+  // Stops |thread| and ensure that it does not have an entry in
   // /proc/self/task/ from the point of view of the current thread. This is
   // the way to stop threads before calling IsSingleThreaded().
   static bool StopThreadAndWatchProcFS(int proc_fd, base::Thread* thread);
diff --git a/sandbox/linux/services/thread_helpers_unittests.cc b/sandbox/linux/services/thread_helpers_unittests.cc
index 7357a0c..1461c35 100644
--- a/sandbox/linux/services/thread_helpers_unittests.cc
+++ b/sandbox/linux/services/thread_helpers_unittests.cc
@@ -59,7 +59,7 @@
   ASSERT_TRUE(ThreadHelpers::IsSingleThreaded());
 
   base::Thread thread("sandbox_tests");
-  ASSERT_TRUE(thread.Start());
+  ASSERT_TRUE(ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread));
   ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
   ASSERT_FALSE(ThreadHelpers::IsSingleThreaded());
   // Explicitly stop the thread here to not pollute the next test.
@@ -82,7 +82,8 @@
   // Iterate to check for race conditions.
   for (int i = 0; i < GetRaceTestIterations(); ++i) {
     base::Thread thread("sandbox_tests");
-    ASSERT_TRUE(thread.Start());
+    ASSERT_TRUE(
+        ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread));
     ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
     // Explicitly stop the thread here to not pollute the next test.
     ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(proc_fd.fd(), &thread));
@@ -97,7 +98,8 @@
   // 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_TRUE(
+        ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread));
     ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
 
     ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(proc_fd.fd(), &thread));
@@ -107,14 +109,17 @@
 }
 
 SANDBOX_TEST(ThreadHelpers, AssertSingleThreadedAfterThreadStopped) {
+  ScopedProc proc_fd;
   SANDBOX_ASSERT(ThreadHelpers::IsSingleThreaded());
 
   base::Thread thread1("sandbox_tests");
   base::Thread thread2("sandbox_tests");
 
   for (int i = 0; i < GetRaceTestIterations(); ++i) {
-    SANDBOX_ASSERT(thread1.Start());
-    SANDBOX_ASSERT(thread2.Start());
+    SANDBOX_ASSERT(
+        ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread1));
+    SANDBOX_ASSERT(
+        ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread2));
     SANDBOX_ASSERT(!ThreadHelpers::IsSingleThreaded());
 
     thread1.Stop();
diff --git a/sandbox/linux/services/yama.cc b/sandbox/linux/services/yama.cc
index 151f4bd..274443c 100644
--- a/sandbox/linux/services/yama.cc
+++ b/sandbox/linux/services/yama.cc
@@ -4,6 +4,7 @@
 
 #include "sandbox/linux/services/yama.h"
 
+#include <errno.h>
 #include <fcntl.h>
 #include <sys/prctl.h>
 #include <sys/stat.h>
diff --git a/sandbox/linux/services/yama_unittests.cc b/sandbox/linux/services/yama_unittests.cc
index a4100a6..0e8355d 100644
--- a/sandbox/linux/services/yama_unittests.cc
+++ b/sandbox/linux/services/yama_unittests.cc
@@ -10,6 +10,7 @@
 #include <unistd.h>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/compiler_specific.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/strings/string_util.h"
@@ -30,8 +31,9 @@
   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);
+  bool is_3_dot_2 = base::StartsWith(
+      base::SysInfo::OperatingSystemVersion(), "3.2",
+      base::CompareCase::INSENSITIVE_ASCII);
   if (is_kernel_64bit && is_linux && is_3_dot_2)
     return true;
 #endif  // defined(__i386__)
@@ -151,14 +153,12 @@
   }
 }
 
-void DoNothing() {}
-
 SANDBOX_TEST(Yama, RestrictPtraceIsDefault) {
   if (!Yama::IsPresent() || HasLinux32Bug())
     return;
 
   CHECK(Yama::DisableYamaRestrictions());
-  ScopedProcess process1(base::Bind(&DoNothing));
+  ScopedProcess process1(base::Bind(&base::DoNothing));
 
   if (Yama::IsEnforcing()) {
     // Check that process1 is protected by Yama, even though it has
diff --git a/sandbox/linux/suid/common/sandbox.h b/sandbox/linux/suid/common/sandbox.h
index 99eb7b5..52ef10c 100644
--- a/sandbox/linux/suid/common/sandbox.h
+++ b/sandbox/linux/suid/common/sandbox.h
@@ -17,7 +17,7 @@
 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D";
 static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID";
 
-static const long kSUIDSandboxApiNumber = 1;
+static const int kSUIDSandboxApiNumber = 1;
 static const char kSandboxEnvironmentApiRequest[] = "SBX_CHROME_API_RQ";
 static const char kSandboxEnvironmentApiProvides[] = "SBX_CHROME_API_PRV";
 
diff --git a/sandbox/linux/suid/sandbox.c b/sandbox/linux/suid/sandbox.c
index 3049ae5..187df94 100644
--- a/sandbox/linux/suid/sandbox.c
+++ b/sandbox/linux/suid/sandbox.c
@@ -378,24 +378,27 @@
 bool CheckAndExportApiVersion() {
   // Check the environment to see if a specific API version was requested.
   // assume version 0 if none.
-  long api_number = -1;
+  int 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)
+    long long_api_number = strtol(api_string, &endptr, 10);
+    if (!endptr || *endptr || errno != 0 || long_api_number < INT_MIN ||
+        long_api_number > INT_MAX) {
       return false;
+    }
+    api_number = long_api_number;
   }
 
   // Warn only for now.
   if (api_number != kSUIDSandboxApiNumber) {
     fprintf(
         stderr,
-        "The setuid sandbox provides API version %ld, "
-        "but you need %ld\n"
+        "The setuid sandbox provides API version %d, "
+        "but you need %d\n"
         "Please read "
         "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment."
         "\n\n",
@@ -406,8 +409,7 @@
   // 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);
+  snprintf(version_string, sizeof(version_string), "%d", kSUIDSandboxApiNumber);
   if (setenv(kSandboxEnvironmentApiProvides, version_string, 1)) {
     perror("setenv");
     return false;
@@ -428,7 +430,7 @@
 
   // Allow someone to query our API version
   if (argc == 2 && 0 == strcmp(argv[1], kSuidSandboxGetApiSwitch)) {
-    printf("%ld\n", kSUIDSandboxApiNumber);
+    printf("%d\n", kSUIDSandboxApiNumber);
     return 0;
   }
 
diff --git a/sandbox/linux/syscall_broker/broker_client.cc b/sandbox/linux/syscall_broker/broker_client.cc
index 8d04197..760cf59 100644
--- a/sandbox/linux/syscall_broker/broker_client.cc
+++ b/sandbox/linux/syscall_broker/broker_client.cc
@@ -65,7 +65,7 @@
     }
   }
 
-  Pickle write_pickle;
+  base::Pickle write_pickle;
   write_pickle.WriteInt(syscall_type);
   write_pickle.WriteString(pathname);
   write_pickle.WriteInt(flags);
@@ -78,7 +78,7 @@
   // 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(
+  ssize_t msg_len = base::UnixDomainSocket::SendRecvMsgWithFlags(
       ipc_channel_.get(), reply_buf, sizeof(reply_buf), recvmsg_flags,
       &returned_fd, write_pickle);
   if (msg_len <= 0) {
@@ -87,8 +87,8 @@
     return -ENOMEM;
   }
 
-  Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
-  PickleIterator iter(read_pickle);
+  base::Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
+  base::PickleIterator iter(read_pickle);
   int return_value = -1;
   // Now deserialize the return value and eventually return the file
   // descriptor.
diff --git a/sandbox/linux/syscall_broker/broker_host.cc b/sandbox/linux/syscall_broker/broker_host.cc
index fe28b47..8b78b1b 100644
--- a/sandbox/linux/syscall_broker/broker_host.cc
+++ b/sandbox/linux/syscall_broker/broker_host.cc
@@ -4,6 +4,7 @@
 
 #include "sandbox/linux/syscall_broker/broker_host.h"
 
+#include <errno.h>
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -59,7 +60,7 @@
 void OpenFileForIPC(const BrokerPolicy& policy,
                     const std::string& requested_filename,
                     int flags,
-                    Pickle* write_pickle,
+                    base::Pickle* write_pickle,
                     std::vector<int>* opened_files) {
   DCHECK(write_pickle);
   DCHECK(opened_files);
@@ -91,7 +92,7 @@
 void AccessFileForIPC(const BrokerPolicy& policy,
                       const std::string& requested_filename,
                       int mode,
-                      Pickle* write_pickle) {
+                      base::Pickle* write_pickle) {
   DCHECK(write_pickle);
   const char* file_to_access = NULL;
   const bool safe_to_access_file = policy.GetFileNameIfAllowedToAccess(
@@ -116,14 +117,14 @@
 bool HandleRemoteCommand(const BrokerPolicy& policy,
                          IPCCommand command_type,
                          int reply_ipc,
-                         PickleIterator iter) {
+                         base::PickleIterator iter) {
   // Currently all commands have two arguments: filename and flags.
   std::string requested_filename;
   int flags = 0;
   if (!iter.ReadString(&requested_filename) || !iter.ReadInt(&flags))
     return false;
 
-  Pickle write_pickle;
+  base::Pickle write_pickle;
   std::vector<int> opened_files;
 
   switch (command_type) {
@@ -140,7 +141,7 @@
   }
 
   CHECK_LE(write_pickle.size(), kMaxMessageLength);
-  ssize_t sent = UnixDomainSocket::SendMsg(
+  ssize_t sent = base::UnixDomainSocket::SendMsg(
       reply_ipc, write_pickle.data(), write_pickle.size(), opened_files);
 
   // Close anything we have opened in this process.
@@ -176,8 +177,8 @@
   ScopedVector<base::ScopedFD> fds;
   char buf[kMaxMessageLength];
   errno = 0;
-  const ssize_t msg_len =
-      UnixDomainSocket::RecvMsg(ipc_channel_.get(), buf, sizeof(buf), &fds);
+  const ssize_t msg_len = base::UnixDomainSocket::RecvMsg(
+      ipc_channel_.get(), buf, sizeof(buf), &fds);
 
   if (msg_len == 0 || (msg_len == -1 && errno == ECONNRESET)) {
     // EOF from the client, or the client died, we should die.
@@ -194,8 +195,8 @@
 
   base::ScopedFD temporary_ipc(fds[0]->Pass());
 
-  Pickle pickle(buf, msg_len);
-  PickleIterator iter(pickle);
+  base::Pickle pickle(buf, msg_len);
+  base::PickleIterator iter(pickle);
   int command_type;
   if (iter.ReadInt(&command_type)) {
     bool command_handled = false;
diff --git a/sandbox/linux/syscall_broker/broker_process_unittest.cc b/sandbox/linux/syscall_broker/broker_process_unittest.cc
index bd7ef27..9ad0e71 100644
--- a/sandbox/linux/syscall_broker/broker_process_unittest.cc
+++ b/sandbox/linux/syscall_broker/broker_process_unittest.cc
@@ -541,7 +541,7 @@
   // 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));
+        base::UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds));
   }
 
   const int fd = open_broker.Open(kCpuInfo, O_RDONLY);
diff --git a/sandbox/linux/system_headers/linux_signal.h b/sandbox/linux/system_headers/linux_signal.h
index 5db7fc5..6801b71 100644
--- a/sandbox/linux/system_headers/linux_signal.h
+++ b/sandbox/linux/system_headers/linux_signal.h
@@ -8,6 +8,58 @@
 // NOTE: On some toolchains, signal related ABI is incompatible with Linux's
 // (not undefined, but defined different values and in different memory
 // layouts). So, fill the gap here.
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \
+    defined(__aarch64__)
+
+#define LINUX_SIGHUP 1
+#define LINUX_SIGINT 2
+#define LINUX_SIGQUIT 3
+#define LINUX_SIGABRT 6
+#define LINUX_SIGBUS 7
+#define LINUX_SIGUSR1 10
+#define LINUX_SIGSEGV 11
+#define LINUX_SIGUSR2 12
+#define LINUX_SIGPIPE 13
+#define LINUX_SIGTERM 15
+#define LINUX_SIGCHLD 17
+#define LINUX_SIGSYS 31
+
+#define LINUX_SIG_BLOCK 0
+#define LINUX_SIG_UNBLOCK 1
+
+#define LINUX_SA_SIGINFO 4
+#define LINUX_SA_NODEFER 0x40000000
+#define LINUX_SA_RESTART 0x10000000
+
+#define LINUX_SIG_DFL 0
+
+#elif defined(__mips__)
+
+#define LINUX_SIGHUP 1
+#define LINUX_SIGINT 2
+#define LINUX_SIGQUIT 3
+#define LINUX_SIGABRT 6
+#define LINUX_SIGBUS 10
+#define LINUX_SIGSEGV 11
+#define LINUX_SIGSYS 12
+#define LINUX_SIGPIPE 13
+#define LINUX_SIGTERM 15
+#define LINUX_SIGUSR1 16
+#define LINUX_SIGUSR2 17
+#define LINUX_SIGCHLD 18
+
+#define LINUX_SIG_BLOCK 1
+#define LINUX_SIG_UNBLOCK 2
+
+#define LINUX_SA_SIGINFO 0x00000008
+#define LINUX_SA_NODEFER 0x40000000
+#define LINUX_SA_RESTART 0x10000000
+
+#define LINUX_SIG_DFL 0
+
+#else
+#error "Unsupported platform"
+#endif
 
 #if defined(__native_client_nonsfi__)
 #if !defined(__i386__) && !defined(__arm__)
@@ -16,20 +68,6 @@
 
 #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;
@@ -44,22 +82,27 @@
 
 #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
+static_assert(LINUX_SIGHUP == SIGHUP, "LINUX_SIGHUP == SIGHUP");
+static_assert(LINUX_SIGINT == SIGINT, "LINUX_SIGINT == SIGINT");
+static_assert(LINUX_SIGQUIT == SIGQUIT, "LINUX_SIGQUIT == SIGQUIT");
+static_assert(LINUX_SIGABRT == SIGABRT, "LINUX_SIGABRT == SIGABRT");
+static_assert(LINUX_SIGBUS == SIGBUS, "LINUX_SIGBUS == SIGBUS");
+static_assert(LINUX_SIGUSR1 == SIGUSR1, "LINUX_SIGUSR1 == SIGUSR1");
+static_assert(LINUX_SIGSEGV == SIGSEGV, "LINUX_SIGSEGV == SIGSEGV");
+static_assert(LINUX_SIGUSR2 == SIGUSR2, "LINUX_SIGUSR2 == SIGUSR2");
+static_assert(LINUX_SIGPIPE == SIGPIPE, "LINUX_SIGPIPE == SIGPIPE");
+static_assert(LINUX_SIGTERM == SIGTERM, "LINUX_SIGTERM == SIGTERM");
+static_assert(LINUX_SIGCHLD == SIGCHLD, "LINUX_SIGCHLD == SIGCHLD");
+static_assert(LINUX_SIGSYS == SIGSYS, "LINUX_SIGSYS == SIGSYS");
+static_assert(LINUX_SIG_BLOCK == SIG_BLOCK, "LINUX_SIG_BLOCK == SIG_BLOCK");
+static_assert(LINUX_SIG_UNBLOCK == SIG_UNBLOCK,
+              "LINUX_SIG_UNBLOCK == SIG_UNBLOCK");
+static_assert(LINUX_SA_SIGINFO == SA_SIGINFO, "LINUX_SA_SIGINFO == SA_SIGINFO");
+static_assert(LINUX_SA_NODEFER == SA_NODEFER, "LINUX_SA_NODEFER == SA_NODEFER");
+static_assert(LINUX_SA_RESTART == SA_RESTART, "LINUX_SA_RESTART == SA_RESTART");
+static_assert(LINUX_SIG_DFL == SIG_DFL, "LINUX_SIG_DFL == SIG_DFL");
 
 typedef siginfo_t LinuxSigInfo;
 
@@ -70,4 +113,32 @@
 
 #endif  // !defined(__native_client_nonsfi__)
 
+// struct sigset_t is different size in PNaCl from the Linux's.
+#if defined(__mips__)
+#if !defined(_NSIG_WORDS)
+#define _NSIG_WORDS 4
+#endif
+struct LinuxSigSet {
+  unsigned long sig[_NSIG_WORDS];
+};
+#else
+typedef uint64_t LinuxSigSet;
+#endif
+
+// struct sigaction is different in PNaCl from the Linux's.
+#if defined(__mips__)
+struct LinuxSigAction {
+  unsigned int sa_flags;
+  void (*kernel_handler)(int);
+  LinuxSigSet sa_mask;
+};
+#else
+struct LinuxSigAction {
+  void (*kernel_handler)(int);
+  uint32_t sa_flags;
+  void (*sa_restorer)(void);
+  LinuxSigSet sa_mask;
+};
+#endif
+
 #endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
diff --git a/sandbox/linux/system_headers/linux_time.h b/sandbox/linux/system_headers/linux_time.h
new file mode 100644
index 0000000..e6c8112
--- /dev/null
+++ b/sandbox/linux/system_headers/linux_time.h
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_TIME_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_TIME_H_
+
+#include <time.h>
+
+#if !defined(CLOCK_REALTIME_COARSE)
+#define CLOCK_REALTIME_COARSE 5
+#endif
+
+#if !defined(CLOCK_MONOTONIC_COARSE)
+#define CLOCK_MONOTONIC_COARSE 6
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_TIME_H_
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc
index cfcec96..7ea2815 100644
--- a/sandbox/linux/tests/unit_tests.cc
+++ b/sandbox/linux/tests/unit_tests.cc
@@ -31,8 +31,15 @@
 }
 
 int GetSubProcessTimeoutTimeInSeconds() {
-  // 10s ought to be enough for anybody.
+#ifdef NDEBUG
+  // Chromecast build lab devices need this much time to complete.
+  // They only run in release.
+  return 30;
+#else
+  // Want a shorter timeout than test runner to get a useful callstack
+  // in debug.
   return 10;
+#endif
 }
 
 // Returns the number of threads of the current process or -1.
diff --git a/sandbox/mac/BUILD.gn b/sandbox/mac/BUILD.gn
index 13960bf..cdaf527 100644
--- a/sandbox/mac/BUILD.gn
+++ b/sandbox/mac/BUILD.gn
@@ -57,6 +57,8 @@
     "os_compatibility.h",
     "policy.cc",
     "policy.h",
+    "pre_exec_delegate.cc",
+    "pre_exec_delegate.h",
     "xpc.cc",
     "xpc.h",
     "xpc_message_server.cc",
diff --git a/sandbox/mac/bootstrap_sandbox.cc b/sandbox/mac/bootstrap_sandbox.cc
index a90f570..e8997f9 100644
--- a/sandbox/mac/bootstrap_sandbox.cc
+++ b/sandbox/mac/bootstrap_sandbox.cc
@@ -10,18 +10,53 @@
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/mach_logging.h"
+#include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "sandbox/mac/launchd_interception_server.h"
+#include "sandbox/mac/pre_exec_delegate.h"
 
 namespace sandbox {
 
-const int kNotAPolicy = -1;
+namespace {
+
+struct SandboxCheckInRequest {
+  mach_msg_header_t header;
+  uint64_t token;
+};
+
+struct SandboxCheckInReply {
+  mach_msg_header_t header;
+  mach_msg_body_t body;
+  mach_msg_port_descriptor_t bootstrap_port;
+};
+
+class ScopedCallMachMsgDestroy {
+ public:
+  explicit ScopedCallMachMsgDestroy(mach_msg_header_t* message)
+      : message_(message) {}
+
+  ~ScopedCallMachMsgDestroy() {
+    if (message_)
+      mach_msg_destroy(message_);
+  }
+
+  void Disarm() {
+    message_ = nullptr;
+  }
+
+ private:
+  mach_msg_header_t* message_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCallMachMsgDestroy);
+};
+
+}  // namespace
 
 // 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()));
+  sandbox->launchd_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.
@@ -33,17 +68,67 @@
         << "Failed to bootstrap_check_in the sandbox server.";
     return null.Pass();
   }
-  base::mac::ScopedMachReceiveRight scoped_port(port);
+  sandbox->check_in_port_.reset(port);
+
+  BootstrapSandbox* __block sandbox_ptr = sandbox.get();
+  sandbox->check_in_server_.reset(new base::DispatchSourceMach(
+      "org.chromium.sandbox.BootstrapClientManager",
+      sandbox->check_in_port_.get(),
+      ^{ sandbox_ptr->HandleChildCheckIn(); }));
+  sandbox->check_in_server_->Resume();
 
   // Start the sandbox server.
-  if (sandbox->server_->Initialize(scoped_port.get()))
-    ignore_result(scoped_port.release());  // Transferred to server_.
-  else
+  if (!sandbox->launchd_server_->Initialize(MACH_PORT_NULL))
     return null.Pass();
 
   return sandbox.Pass();
 }
 
+// Warning: This function must be safe to call in
+// PreExecDelegate::RunAsyncSafe().
+// static
+bool BootstrapSandbox::ClientCheckIn(mach_port_t sandbox_server_port,
+                                     uint64_t sandbox_token,
+                                     mach_port_t* new_bootstrap_port) {
+  // Create a reply port for the check in message.
+  mach_port_t reply_port;
+  kern_return_t kr = mach_port_allocate(mach_task_self(),
+                                        MACH_PORT_RIGHT_RECEIVE,
+                                        &reply_port);
+  if (kr != KERN_SUCCESS) {
+    RAW_LOG(ERROR, "ClientCheckIn: mach_port_allocate failed");
+    return false;
+  }
+  base::mac::ScopedMachReceiveRight scoped_reply_port(reply_port);
+
+  // Check in with the sandbox server, presenting the |sandbox_token| in
+  // exchange for a new task bootstrap port.
+  union {
+    SandboxCheckInRequest request;
+    struct {
+      SandboxCheckInReply reply;
+      mach_msg_trailer_t trailer;
+    };
+  } msg = {};
+  msg.request.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
+                                                MACH_MSG_TYPE_MAKE_SEND_ONCE);
+  msg.request.header.msgh_remote_port = sandbox_server_port;
+  msg.request.header.msgh_local_port = reply_port;
+  msg.request.header.msgh_size = sizeof(msg);
+  msg.request.token = sandbox_token;
+
+  kr = mach_msg(&msg.request.header, MACH_SEND_MSG | MACH_RCV_MSG,
+                sizeof(msg.request), sizeof(msg), reply_port,
+                MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  if (kr == KERN_SUCCESS) {
+    *new_bootstrap_port = msg.reply.bootstrap_port.name;
+    return true;
+  } else {
+    RAW_LOG(ERROR, "ClientCheckIn: mach_msg failed");
+    return false;
+  }
+}
+
 BootstrapSandbox::~BootstrapSandbox() {
 }
 
@@ -51,48 +136,35 @@
     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) {
+scoped_ptr<PreExecDelegate> BootstrapSandbox::NewClient(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()";
+  DCHECK(policies_.find(sandbox_policy_id) != policies_.end());
 
-  // 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;
+  uint64_t token;
+  while (true) {
+    token = base::RandUint64();
+    if (awaiting_processes_.find(token) == awaiting_processes_.end())
+      break;
   }
 
-  effective_policy_id_ = kNotAPolicy;
+  awaiting_processes_[token] = sandbox_policy_id;
+  return make_scoped_ptr(new PreExecDelegate(server_bootstrap_name_, token));
 }
 
-void BootstrapSandbox::ChildDied(base::ProcessHandle handle) {
+void BootstrapSandbox::RevokeToken(uint64_t token) {
+  base::AutoLock lock(lock_);
+  const auto& it = awaiting_processes_.find(token);
+  if (it != awaiting_processes_.end())
+    awaiting_processes_.erase(it);
+}
+
+void BootstrapSandbox::InvalidateClient(base::ProcessHandle handle) {
   base::AutoLock lock(lock_);
   const auto& it = sandboxed_processes_.find(handle);
   if (it != sandboxed_processes_.end())
@@ -103,26 +175,18 @@
     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;
+    return &policies_.find(process->second)->second;
   }
 
-  if (policy_id == kNotAPolicy)
-    return NULL;
-
-  return &policies_.find(policy_id)->second;
+  return nullptr;
 }
 
 BootstrapSandbox::BootstrapSandbox()
     : server_bootstrap_name_(
           base::StringPrintf("%s.sandbox.%d", base::mac::BaseBundleID(),
               getpid())),
-      real_bootstrap_port_(MACH_PORT_NULL),
-      effective_policy_id_(kNotAPolicy) {
+      real_bootstrap_port_(MACH_PORT_NULL) {
   mach_port_t port = MACH_PORT_NULL;
   kern_return_t kr = task_get_special_port(
       mach_task_self(), TASK_BOOTSTRAP_PORT, &port);
@@ -130,4 +194,66 @@
   real_bootstrap_port_.reset(port);
 }
 
+void BootstrapSandbox::HandleChildCheckIn() {
+  struct {
+    SandboxCheckInRequest request;
+    mach_msg_audit_trailer_t trailer;
+  } msg = {};
+  msg.request.header.msgh_local_port = check_in_port_.get();
+  msg.request.header.msgh_size = sizeof(msg.request);
+  const mach_msg_option_t kOptions = MACH_RCV_MSG |
+      MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
+      MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
+  kern_return_t kr = mach_msg(&msg.request.header, kOptions, 0,
+                              sizeof(msg), check_in_port_.get(),
+                              MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "HandleChildCheckIn mach_msg MACH_RCV_MSG";
+    return;
+  }
+
+  // Call mach_msg_destroy to clean up the reply send-once right.
+  ScopedCallMachMsgDestroy message_destroyer(&msg.request.header);
+
+  pid_t client_pid;
+  audit_token_to_au32(msg.trailer.msgh_audit, nullptr, nullptr, nullptr,
+      nullptr, nullptr, &client_pid, nullptr, nullptr);
+
+  {
+    base::AutoLock lock(lock_);
+
+    auto awaiting_it = awaiting_processes_.find(msg.request.token);
+    if (awaiting_it == awaiting_processes_.end()) {
+      LOG(ERROR) << "Received sandbox check-in message from unknown client.";
+      return;
+    }
+
+    CHECK(sandboxed_processes_.find(client_pid) == sandboxed_processes_.end());
+    sandboxed_processes_[client_pid] = awaiting_it->second;
+    awaiting_processes_.erase(awaiting_it);
+  }
+
+  SandboxCheckInReply reply = {};
+  reply.header.msgh_bits = MACH_MSGH_BITS_REMOTE(msg.request.header.msgh_bits) |
+                           MACH_MSGH_BITS_COMPLEX;
+  reply.header.msgh_remote_port = msg.request.header.msgh_remote_port;
+  reply.header.msgh_size = sizeof(reply);
+  reply.body.msgh_descriptor_count = 1;
+  reply.bootstrap_port.name = launchd_server_->server_port();
+  reply.bootstrap_port.disposition = MACH_MSG_TYPE_MAKE_SEND;
+  reply.bootstrap_port.type = MACH_MSG_PORT_DESCRIPTOR;
+
+  kr = mach_msg(&reply.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
+                sizeof(reply), 0, MACH_PORT_NULL, 100 /*ms*/, MACH_PORT_NULL);
+  if (kr == KERN_SUCCESS) {
+    message_destroyer.Disarm();  // The send-once was consumed at mach_msg().
+  } else {
+    {
+      base::AutoLock lock(lock_);
+      sandboxed_processes_.erase(client_pid);
+    }
+    MACH_LOG(ERROR, kr) << "HandleChildCheckIn mach_msg MACH_SEND_MSG";
+  }
+}
+
 }  // namespace sandbox
diff --git a/sandbox/mac/bootstrap_sandbox.h b/sandbox/mac/bootstrap_sandbox.h
index fd808cd..6e823a4 100644
--- a/sandbox/mac/bootstrap_sandbox.h
+++ b/sandbox/mac/bootstrap_sandbox.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <string>
 
+#include "base/mac/dispatch_source_mach.h"
 #include "base/mac/scoped_mach_port.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/process/process_handle.h"
@@ -20,39 +21,44 @@
 namespace sandbox {
 
 class LaunchdInterceptionServer;
+class PreExecDelegate;
 
 // 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.
+// With this sandbox, the parent process must create the client using the
+// sandbox's PreExecDelegate, which will replace the bootstrap port of the
+// child process. 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.
 //
 // 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.
+// being enforced, it should use NewClient() to create a PreExecDelegate for
+// a sandbox policy ID and set it to the base::LaunchOptions.pre_exec_delegate.
 //
-// All methods of this class may be called from any thread, but
-// PrepareToForkWithPolicy() and FinishedFork() must be non-nested and balanced.
+// When a child process exits, the parent should call InvalidateClient() to
+// clean up any mappings in this class.
+//
+// All methods of this class may be called from any thread.
 class SANDBOX_EXPORT BootstrapSandbox {
  public:
   // Creates a new sandbox manager. Returns NULL on failure.
   static scoped_ptr<BootstrapSandbox> Create();
 
+  // For use in newly created child processes. Checks in with the bootstrap
+  // sandbox manager running in the parent process. |sandbox_server_port| is
+  // the Mach send right to the sandbox |check_in_server_| (in the child).
+  // |sandbox_token| is the assigned token. On return, |bootstrap_port| is set
+  // to a new Mach send right to be used in the child as the task's bootstrap
+  // port.
+  static bool ClientCheckIn(mach_port_t sandbox_server_port,
+                            uint64_t sandbox_token,
+                            mach_port_t* bootstrap_port);
+
   ~BootstrapSandbox();
 
   // Registers a bootstrap policy associated it with an identifier. The
@@ -60,30 +66,33 @@
   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);
+  // Creates a new PreExecDelegate to pass to base::LaunchOptions. This will
+  // enforce the policy with |sandbox_policy_id| on the new process.
+  scoped_ptr<PreExecDelegate> NewClient(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);
+  // If a client did not launch properly, the sandbox provided to the
+  // PreExecDelegate should be invalidated using this method.
+  void RevokeToken(uint64_t token);
 
   // Called in the parent when a process has died. It cleans up the references
   // to the process.
-  void ChildDied(base::ProcessHandle handle);
+  void InvalidateClient(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_; }
+  mach_port_t real_bootstrap_port() const { return real_bootstrap_port_.get(); }
 
  private:
   BootstrapSandbox();
 
+  // Dispatch callout for when a client sends a message on the
+  // |check_in_port_|. If the client message is valid, it will assign the
+  // client from |awaiting_processes_| to |sandboxed_processes_|.
+  void HandleChildCheckIn();
+
   // The name in the system bootstrap server by which the |server_|'s port
   // is known.
   const std::string server_bootstrap_name_;
@@ -95,18 +104,25 @@
   // 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_;
 
+  // The association between a new process' sandbox token and its policy ID.
+  // The entry is removed after the process checks in, and the mapping moves
+  // to |sandboxed_processes_|.
+  std::map<uint64_t, int> awaiting_processes_;
+
   // A Mach IPC message server that is used to intercept and filter bootstrap
   // requests.
-  scoped_ptr<LaunchdInterceptionServer> server_;
+  scoped_ptr<LaunchdInterceptionServer> launchd_server_;
+
+  // The port and dispatch source for receiving client check in messages sent
+  // via ClientCheckIn().
+  base::mac::ScopedMachReceiveRight check_in_port_;
+  scoped_ptr<base::DispatchSourceMach> check_in_server_;
 };
 
 }  // namespace sandbox
diff --git a/sandbox/mac/bootstrap_sandbox_unittest.mm b/sandbox/mac/bootstrap_sandbox_unittest.mm
index 7e5e8b6..467189e 100644
--- a/sandbox/mac/bootstrap_sandbox_unittest.mm
+++ b/sandbox/mac/bootstrap_sandbox_unittest.mm
@@ -12,12 +12,14 @@
 #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/mac/scoped_nsobject.h"
 #include "base/process/kill.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/multiprocess_test.h"
 #include "base/test/test_timeouts.h"
+#include "sandbox/mac/pre_exec_delegate.h"
+#include "sandbox/mac/xpc.h"
 #import "testing/gtest_mac.h"
 #include "testing/multiprocess_func_list.h"
 
@@ -78,6 +80,11 @@
 
 namespace sandbox {
 
+void InitializeXPCIfRequired() {
+  if (base::mac::IsOSYosemiteOrLater())
+    CHECK(InitializeXPC());
+}
+
 class BootstrapSandboxTest : public base::MultiProcessTest {
  public:
   void SetUp() override {
@@ -89,6 +96,7 @@
 
   BootstrapSandboxPolicy BaselinePolicy() {
     BootstrapSandboxPolicy policy;
+    policy.rules["com.apple.cfprefsd.daemon"] = Rule(POLICY_ALLOW);
     if (base::mac::IsOSSnowLeopard())
       policy.rules["com.apple.SecurityServer"] = Rule(POLICY_ALLOW);
     return policy;
@@ -97,12 +105,14 @@
   void RunChildWithPolicy(int policy_id,
                           const char* child_name,
                           base::ProcessHandle* out_pid) {
-    sandbox_->PrepareToForkWithPolicy(policy_id);
+    scoped_ptr<PreExecDelegate> pre_exec_delegate(
+        sandbox_->NewClient(policy_id));
+
     base::LaunchOptions options;
-    options.replacement_bootstrap_name = sandbox_->server_bootstrap_name();
+    options.pre_exec_delegate = pre_exec_delegate.get();
+
     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);
@@ -169,6 +179,8 @@
 }
 
 MULTIPROCESS_TEST_MAIN(PostNotification) {
+  InitializeXPCIfRequired();
+
   [[NSDistributedNotificationCenter defaultCenter]
       postNotificationName:kTestNotification
                     object:[NSString stringWithFormat:@"%d", getpid()]];
@@ -186,6 +198,8 @@
 }
 
 MULTIPROCESS_TEST_MAIN(PolicyDenyError) {
+  InitializeXPCIfRequired();
+
   mach_port_t port = MACH_PORT_NULL;
   kern_return_t kr = bootstrap_look_up(bootstrap_port, kTestServer,
       &port);
@@ -209,6 +223,8 @@
 }
 
 MULTIPROCESS_TEST_MAIN(PolicyDenyDummyPort) {
+  InitializeXPCIfRequired();
+
   mach_port_t port = MACH_PORT_NULL;
   kern_return_t kr = bootstrap_look_up(bootstrap_port, kTestServer,
       &port);
@@ -274,6 +290,8 @@
 }
 
 MULTIPROCESS_TEST_MAIN(PolicySubstitutePort) {
+  InitializeXPCIfRequired();
+
   mach_port_t port = MACH_PORT_NULL;
   kern_return_t kr = bootstrap_look_up(bootstrap_port, kTestServer, &port);
   CHECK_EQ(KERN_SUCCESS, kr);
@@ -391,6 +409,8 @@
 }
 
 MULTIPROCESS_TEST_MAIN(DefaultRuleAllow) {
+  InitializeXPCIfRequired();
+
   [[NSDistributedNotificationCenter defaultCenter]
       postNotificationName:kTestNotification
                     object:[NSString stringWithFormat:@"%d", getpid()]];
@@ -436,12 +456,12 @@
   sandbox_->RegisterSandboxPolicy(kTestPolicyId, policy);
 
   // Launch the child.
-  sandbox_->PrepareToForkWithPolicy(kTestPolicyId);
+  scoped_ptr<PreExecDelegate> pre_exec_delegate(
+      sandbox_->NewClient(kTestPolicyId));
   base::LaunchOptions options;
-  options.replacement_bootstrap_name = sandbox_->server_bootstrap_name();
+  options.pre_exec_delegate = pre_exec_delegate.get();
   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;
@@ -472,6 +492,8 @@
 }
 
 MULTIPROCESS_TEST_MAIN(ChildOutliveSandbox) {
+  InitializeXPCIfRequired();
+
   // Get the synchronization channel.
   mach_port_t port = MACH_PORT_NULL;
   CHECK_EQ(KERN_SUCCESS, bootstrap_look_up(bootstrap_port, "sync", &port));
diff --git a/sandbox/mac/launchd_interception_server.cc b/sandbox/mac/launchd_interception_server.cc
index 06f1081..6ce61f6 100644
--- a/sandbox/mac/launchd_interception_server.cc
+++ b/sandbox/mac/launchd_interception_server.cc
@@ -7,9 +7,12 @@
 #include <servers/bootstrap.h>
 
 #include "base/logging.h"
+#include "base/mac/mac_util.h"
 #include "base/mac/mach_logging.h"
 #include "sandbox/mac/bootstrap_sandbox.h"
 #include "sandbox/mac/mach_message_server.h"
+#include "sandbox/mac/os_compatibility.h"
+#include "sandbox/mac/xpc_message_server.h"
 
 namespace sandbox {
 
@@ -21,8 +24,9 @@
 LaunchdInterceptionServer::LaunchdInterceptionServer(
     const BootstrapSandbox* sandbox)
     : sandbox_(sandbox),
+      xpc_launchd_(false),
       sandbox_port_(MACH_PORT_NULL),
-      compat_shim_(GetLaunchdCompatibilityShim()) {
+      compat_shim_(OSCompatibility::CreateForPlatform()) {
 }
 
 LaunchdInterceptionServer::~LaunchdInterceptionServer() {
@@ -40,21 +44,28 @@
     return false;
   }
   sandbox_port_.reset(port);
-  if ((kr = mach_port_insert_right(task, sandbox_port_, sandbox_port_,
-          MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)) {
+  if ((kr = mach_port_insert_right(task, sandbox_port_.get(),
+          sandbox_port_.get(), 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_);
+  sandbox_send_port_.reset(sandbox_port_.get());
 
-  message_server_.reset(
-      new MachMessageServer(this, server_receive_right, kBufferSize));
+  if (base::mac::IsOSYosemiteOrLater()) {
+    message_server_.reset(new XPCMessageServer(this, server_receive_right));
+    xpc_launchd_ = true;
+  } else {
+    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;
+  const uint64_t message_subsystem =
+      compat_shim_->GetMessageSubsystem(request);
+  const uint64_t message_id = compat_shim_->GetMessageID(request);
+  VLOG(3) << "Incoming message #" << message_subsystem << "," << message_id;
 
   pid_t sender_pid = message_server_->GetMessageSenderPID(request);
   const BootstrapSandboxPolicy* policy =
@@ -67,13 +78,16 @@
     return;
   }
 
-  if (message_id == compat_shim_.msg_id_look_up2) {
+  if (compat_shim_->IsServiceLookUpRequest(request)) {
     // 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) {
+  } else if (compat_shim_->IsVprocSwapInteger(request)) {
     // Ensure that any vproc_swap_integer requests are safe.
     HandleSwapInteger(request);
+  } else if (compat_shim_->IsXPCDomainManagement(request)) {
+    // XPC domain management requests just require an ACK.
+    message_server_->SendReply(message_server_->CreateReply(request));
   } else {
     // All other messages are not permitted.
     VLOG(1) << "Rejecting unhandled message #" << message_id;
@@ -85,7 +99,7 @@
     IPCMessage request,
     const BootstrapSandboxPolicy* policy) {
   const std::string request_service_name(
-      compat_shim_.look_up2_get_request_name(request));
+      compat_shim_->GetServiceLookupName(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
@@ -122,13 +136,13 @@
       result_port = rule.substitute_port;
 
     IPCMessage reply = message_server_->CreateReply(request);
-    compat_shim_.look_up2_fill_reply(reply, result_port);
+    compat_shim_->WriteServiceLookUpReply(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);
+      compat_shim_->WriteServiceLookUpReply(reply, MACH_PORT_NULL);
   } else {
     NOTREACHED();
   }
@@ -138,7 +152,7 @@
   // 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)) {
+  if (compat_shim_->IsSwapIntegerReadOnly(request)) {
     VLOG(2) << "Forwarding vproc swap_integer message.";
     ForwardMessage(request);
   } else {
@@ -147,6 +161,18 @@
   }
 }
 void LaunchdInterceptionServer::ForwardMessage(IPCMessage request) {
+  // If launchd is using XPC, then when the request is forwarded, it must
+  // contain a valid domain port. Because the client processes are sandboxed,
+  // they have not had their launchd domains uncorked (and launchd will
+  // reject the message as being from an invalid client). Instead, provide the
+  // original bootstrap as the domain port, so launchd services the request
+  // as if it were coming from the sandbox host process (this).
+  if (xpc_launchd_) {
+    // xpc_dictionary_set_mach_send increments the send right count.
+    xpc_dictionary_set_mach_send(request.xpc, "domain-port",
+                                 sandbox_->real_bootstrap_port());
+  }
+
   message_server_->ForwardMessage(request, sandbox_->real_bootstrap_port());
 }
 
diff --git a/sandbox/mac/launchd_interception_server.h b/sandbox/mac/launchd_interception_server.h
index 144d67d..0375ca2 100644
--- a/sandbox/mac/launchd_interception_server.h
+++ b/sandbox/mac/launchd_interception_server.h
@@ -10,12 +10,12 @@
 #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;
+class OSCompatibility;
 
 // 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
@@ -56,6 +56,9 @@
   // The Mach IPC server.
   scoped_ptr<MessageServer> message_server_;
 
+  // Whether or not the system is using an XPC-based launchd.
+  bool xpc_launchd_;
+
   // 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_;
@@ -65,7 +68,7 @@
 
   // The compatibility shim that handles differences in message header IDs and
   // request/reply structures between different OS X versions.
-  const LaunchdCompatibilityShim compat_shim_;
+  scoped_ptr<OSCompatibility> compat_shim_;
 };
 
 }  // namespace sandbox
diff --git a/sandbox/mac/os_compatibility.cc b/sandbox/mac/os_compatibility.cc
index 6624f3a..f1ad528 100644
--- a/sandbox/mac/os_compatibility.cc
+++ b/sandbox/mac/os_compatibility.cc
@@ -8,6 +8,7 @@
 #include <unistd.h>
 
 #include "base/mac/mac_util.h"
+#include "sandbox/mac/xpc.h"
 
 namespace sandbox {
 
@@ -69,67 +70,140 @@
   return len;
 }
 
-uint64_t MachGetMessageID(const IPCMessage message) {
-  return message.mach->msgh_id;
-}
+class OSCompatibility_10_6 : public OSCompatibility {
+ public:
+  OSCompatibility_10_6() {}
+  ~OSCompatibility_10_6() override {}
 
-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;
-}
+  uint64_t GetMessageSubsystem(const IPCMessage message) override {
+    return (message.mach->msgh_id / 100) * 100;
+  }
 
-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;
-}
+  uint64_t GetMessageID(const IPCMessage message) override {
+    return message.mach->msgh_id;
+  }
 
-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;
-}
+  bool IsServiceLookUpRequest(const IPCMessage message) override {
+    return GetMessageID(message) == 404;
+  }
+
+  bool IsVprocSwapInteger(const IPCMessage message) override {
+    return GetMessageID(message) == 416;
+  }
+
+  bool IsXPCDomainManagement(const IPCMessage message) override {
+    return false;
+  }
+
+  std::string GetServiceLookupName(const IPCMessage message) override {
+    return GetRequestName<look_up2_request_10_6>(message);
+  }
+
+  void WriteServiceLookUpReply(IPCMessage message,
+                               mach_port_t service_port) override {
+    auto reply = reinterpret_cast<look_up2_reply_10_6*>(message.mach);
+    reply->Head.msgh_size = sizeof(*reply);
+    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 = service_port;
+    reply->service_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+    reply->service_port.type = MACH_MSG_PORT_DESCRIPTOR;
+  }
+
+  bool IsSwapIntegerReadOnly(const IPCMessage message) override {
+    auto request =
+        reinterpret_cast<const swap_integer_request_10_6*>(message.mach);
+    return request->inkey == 0 && request->inval == 0 && request->outkey != 0;
+  }
+
+ protected:
+  // The 10.6 and 10.7 implementations are the same except for struct offsets,
+  // so provide this templatized helper.
+  template <typename R>
+  static std::string GetRequestName(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;
+  }
+};
+
+class OSCompatibility_10_7 : public OSCompatibility_10_6 {
+ public:
+  OSCompatibility_10_7() {}
+  ~OSCompatibility_10_7() override {}
+
+  std::string GetServiceLookupName(const IPCMessage message) override {
+    return GetRequestName<look_up2_request_10_7>(message);
+  }
+};
+
+class OSCompatibility_10_10 : public OSCompatibility {
+ public:
+  OSCompatibility_10_10() {}
+  ~OSCompatibility_10_10() override {}
+
+  uint64_t GetMessageSubsystem(const IPCMessage message) override {
+    return xpc_dictionary_get_uint64(message.xpc, "subsystem");
+  }
+
+  uint64_t GetMessageID(const IPCMessage message) override {
+    return xpc_dictionary_get_uint64(message.xpc, "routine");
+  }
+
+  bool IsServiceLookUpRequest(const IPCMessage message) override {
+    uint64_t subsystem = GetMessageSubsystem(message);
+    uint64_t id = GetMessageID(message);
+    // Lookup requests in XPC can either go through the Mach bootstrap subsytem
+    // (5) from bootstrap_look_up(), or the XPC domain subsystem (3) for
+    // xpc_connection_create(). Both use the same message format.
+    return (subsystem == 5 && id == 207) || (subsystem == 3 && id == 804);
+  }
+
+  bool IsVprocSwapInteger(const IPCMessage message) override {
+    return GetMessageSubsystem(message) == 6 && GetMessageID(message) == 301;
+  }
+
+  bool IsXPCDomainManagement(const IPCMessage message) override {
+    return GetMessageSubsystem(message) == 3;
+  }
+
+  std::string GetServiceLookupName(const IPCMessage message) override {
+    const char* name = xpc_dictionary_get_string(message.xpc, "name");
+    const size_t name_length = strnlen(name, BOOTSTRAP_MAX_NAME_LEN);
+    return std::string(name, name_length);
+  }
+
+  void WriteServiceLookUpReply(IPCMessage message,
+                               mach_port_t service_port) override {
+    xpc_dictionary_set_mach_send(message.xpc, "port", service_port);
+  }
+
+  bool IsSwapIntegerReadOnly(const IPCMessage message) override {
+    return xpc_dictionary_get_bool(message.xpc, "set") == false &&
+           xpc_dictionary_get_uint64(message.xpc, "ingsk") == 0 &&
+           xpc_dictionary_get_int64(message.xpc, "in") == 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;
+// static
+scoped_ptr<OSCompatibility> OSCompatibility::CreateForPlatform() {
+  if (base::mac::IsOSSnowLeopard())
+    return make_scoped_ptr(new OSCompatibility_10_6());
+  else if (base::mac::IsOSLionOrLater() && base::mac::IsOSMavericksOrEarlier())
+    return make_scoped_ptr(new OSCompatibility_10_7());
+  else
+    return make_scoped_ptr(new OSCompatibility_10_10());
 }
 
+OSCompatibility::~OSCompatibility() {}
+
 }  // namespace sandbox
diff --git a/sandbox/mac/os_compatibility.h b/sandbox/mac/os_compatibility.h
index 1205cd6..a1f51f2 100644
--- a/sandbox/mac/os_compatibility.h
+++ b/sandbox/mac/os_compatibility.h
@@ -16,44 +16,46 @@
 
 #include <string>
 
+#include "base/memory/scoped_ptr.h"
 #include "sandbox/mac/message_server.h"
 
 namespace sandbox {
 
-typedef uint64_t (*IPCMessageGetID)(const IPCMessage);
+class OSCompatibility {
+ public:
+  // Creates an OSCompatibility instance for the current OS X version.
+  static scoped_ptr<OSCompatibility> CreateForPlatform();
 
-typedef std::string (*LookUp2GetRequestName)(const IPCMessage);
-typedef void (*LookUp2FillReply)(IPCMessage, mach_port_t service_port);
+  virtual ~OSCompatibility();
 
-typedef bool (*SwapIntegerIsGetOnly)(const IPCMessage);
+  // Gets the message and subsystem ID of an IPC message.
+  virtual uint64_t GetMessageSubsystem(const IPCMessage message) = 0;
+  virtual uint64_t GetMessageID(const IPCMessage message) = 0;
 
-struct LaunchdCompatibilityShim {
-  // Gets the message ID of an IPC message.
-  IPCMessageGetID ipc_message_get_id;
+  // Returns true if the message is a Launchd look up request.
+  virtual bool IsServiceLookUpRequest(const IPCMessage message) = 0;
 
-  // The msgh_id for look_up2.
-  uint64_t msg_id_look_up2;
+  // Returns true if the message is a Launchd vproc swap_integer request.
+  virtual bool IsVprocSwapInteger(const IPCMessage message) = 0;
 
-  // The msgh_id for swap_integer.
-  uint64_t msg_id_swap_integer;
+  // Returns true if the message is an XPC domain management message.
+  virtual bool IsXPCDomainManagement(const IPCMessage message) = 0;
 
   // 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;
+  virtual std::string GetServiceLookupName(const IPCMessage message) = 0;
 
   // 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;
+  virtual void WriteServiceLookUpReply(IPCMessage reply,
+                                       mach_port_t service_port) = 0;
 
   // 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;
+  virtual bool IsSwapIntegerReadOnly(const IPCMessage message) = 0;
 };
 
-// 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/pre_exec_delegate.cc b/sandbox/mac/pre_exec_delegate.cc
new file mode 100644
index 0000000..adf40a0
--- /dev/null
+++ b/sandbox/mac/pre_exec_delegate.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.
+
+#include "sandbox/mac/pre_exec_delegate.h"
+
+#include <mach/mach.h>
+#include <servers/bootstrap.h>
+
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "sandbox/mac/bootstrap_sandbox.h"
+#include "sandbox/mac/xpc.h"
+
+namespace sandbox {
+
+PreExecDelegate::PreExecDelegate(
+    const std::string& sandbox_server_bootstrap_name,
+    uint64_t sandbox_token)
+    : sandbox_server_bootstrap_name_(sandbox_server_bootstrap_name),
+      sandbox_server_bootstrap_name_ptr_(
+          sandbox_server_bootstrap_name_.c_str()),
+      sandbox_token_(sandbox_token),
+      is_yosemite_or_later_(base::mac::IsOSYosemiteOrLater()),
+      look_up_message_(CreateBootstrapLookUpMessage()) {
+}
+
+PreExecDelegate::~PreExecDelegate() {}
+
+void PreExecDelegate::RunAsyncSafe() {
+  mach_port_t sandbox_server_port = MACH_PORT_NULL;
+  kern_return_t kr = DoBootstrapLookUp(&sandbox_server_port);
+  if (kr != KERN_SUCCESS)
+    RAW_LOG(FATAL, "Failed to look up bootstrap sandbox server port.");
+
+  mach_port_t new_bootstrap_port = MACH_PORT_NULL;
+  if (!BootstrapSandbox::ClientCheckIn(sandbox_server_port,
+                                       sandbox_token_,
+                                       &new_bootstrap_port)) {
+    RAW_LOG(FATAL, "Failed to check in with sandbox server.");
+  }
+
+  kr = task_set_bootstrap_port(mach_task_self(), new_bootstrap_port);
+  if (kr != KERN_SUCCESS)
+    RAW_LOG(FATAL, "Failed to replace bootstrap port.");
+
+  // On OS X 10.10 and higher, libxpc uses the port stash to transfer the
+  // XPC root port. This is effectively the same connection as the Mach
+  // bootstrap port, but not transferred using the task special port.
+  // Therefore, stash the replacement bootstrap port, so that on 10.10 it
+  // will be retrieved by the XPC code and used as a replacement for the
+  // XPC root port as well.
+  if (is_yosemite_or_later_) {
+    kr = mach_ports_register(mach_task_self(), &new_bootstrap_port, 1);
+    if (kr != KERN_SUCCESS)
+      RAW_LOG(ERROR, "Failed to register replacement bootstrap port.");
+  }
+}
+
+xpc_object_t PreExecDelegate::CreateBootstrapLookUpMessage() {
+  if (is_yosemite_or_later_) {
+    xpc_object_t dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
+    xpc_dictionary_set_uint64(dictionary, "type", 7);
+    xpc_dictionary_set_uint64(dictionary, "handle", 0);
+    xpc_dictionary_set_string(dictionary, "name",
+        sandbox_server_bootstrap_name_ptr_);
+    xpc_dictionary_set_int64(dictionary, "targetpid", 0);
+    xpc_dictionary_set_uint64(dictionary, "flags", 0);
+    xpc_dictionary_set_uint64(dictionary, "subsystem", 5);
+    xpc_dictionary_set_uint64(dictionary, "routine", 207);
+    // Add a NULL port so that the slot in the dictionary is already
+    // allocated.
+    xpc_dictionary_set_mach_send(dictionary, "domain-port", MACH_PORT_NULL);
+    return dictionary;
+  }
+
+  return nullptr;
+}
+
+kern_return_t PreExecDelegate::DoBootstrapLookUp(mach_port_t* out_port) {
+  if (is_yosemite_or_later_) {
+    xpc_dictionary_set_mach_send(look_up_message_, "domain-port",
+        bootstrap_port);
+
+    // |pipe| cannot be created pre-fork() since the |bootstrap_port| will
+    // be invalidated. Deliberately leak |pipe| as well.
+    xpc_pipe_t pipe = xpc_pipe_create_from_port(bootstrap_port, 0);
+    xpc_object_t reply;
+    int rv = xpc_pipe_routine(pipe, look_up_message_, &reply);
+    if (rv != 0) {
+      return xpc_dictionary_get_int64(reply, "error");
+    } else {
+      xpc_object_t port_value = xpc_dictionary_get_value(reply, "port");
+      *out_port = xpc_mach_send_get_right(port_value);
+      return *out_port != MACH_PORT_NULL ? KERN_SUCCESS : KERN_INVALID_RIGHT;
+    }
+  } else {
+    // On non-XPC launchd systems, bootstrap_look_up() is MIG-based and
+    // generally safe.
+    return bootstrap_look_up(bootstrap_port,
+        sandbox_server_bootstrap_name_ptr_, out_port);
+  }
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/pre_exec_delegate.h b/sandbox/mac/pre_exec_delegate.h
new file mode 100644
index 0000000..b84082e
--- /dev/null
+++ b/sandbox/mac/pre_exec_delegate.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 SANDBOX_MAC_PRE_EXEC_DELEGATE_H_
+#define SANDBOX_MAC_PRE_EXEC_DELEGATE_H_
+
+#include "base/process/launch.h"
+#include "sandbox/mac/xpc.h"
+
+namespace sandbox {
+
+// This PreExecDelegate will communicate with the BootstrapSandbox running
+// the Mach server registered under |sandbox_server_bootstrap_name|. It will
+// check in with th BootstrapSandbox using the |sandbox_token| and will
+// replace the task's bootstrap port with one provided by the sandbox.
+class PreExecDelegate : public base::LaunchOptions::PreExecDelegate {
+ public:
+  PreExecDelegate(const std::string& sandbox_server_bootstrap_name,
+                  uint64_t sandbox_token);
+  ~PreExecDelegate() override;
+
+  void RunAsyncSafe() override;
+
+  uint64_t sandbox_token() const { return sandbox_token_; }
+
+ private:
+  // Allocates the bootstrap_look_up IPC message prior to fork().
+  xpc_object_t CreateBootstrapLookUpMessage();
+
+  // Performs a bootstrap_look_up(), either using the pre-allocated message
+  // or the normal routine, depending on the OS X system version.
+  kern_return_t DoBootstrapLookUp(mach_port_t* out_port);
+
+  const std::string sandbox_server_bootstrap_name_;
+  const char* const sandbox_server_bootstrap_name_ptr_;
+  const uint64_t sandbox_token_;
+  const bool is_yosemite_or_later_;
+
+  // If is_yosemite_or_later_, this field is used to hold the pre-allocated XPC
+  // object needed to interact with the bootstrap server in RunAsyncSafe().
+  // This is deliberately leaked in the fork()ed process.
+  xpc_object_t look_up_message_;
+
+  DISALLOW_COPY_AND_ASSIGN(PreExecDelegate);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_PRE_EXEC_DELEGATE_H_
diff --git a/sandbox/mac/sandbox_mac.gypi b/sandbox/mac/sandbox_mac.gypi
index d5013f8..91ad20b 100644
--- a/sandbox/mac/sandbox_mac.gypi
+++ b/sandbox/mac/sandbox_mac.gypi
@@ -19,6 +19,8 @@
         'os_compatibility.h',
         'policy.cc',
         'policy.h',
+        'pre_exec_delegate.cc',
+        'pre_exec_delegate.h',
         'xpc.cc',
         'xpc.h',
         'xpc_message_server.cc',
@@ -111,4 +113,19 @@
       },
     },
   ],
+  'conditions': [
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'sandbox_mac_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'sandbox_mac_unittests',
+          ],
+          'includes': [ '../../build/isolate.gypi' ],
+          'sources': [ '../sandbox_mac_unittests.isolate' ],
+        },
+      ],
+    }],
+  ],
 }
diff --git a/sandbox/mac/xpc_message_server.cc b/sandbox/mac/xpc_message_server.cc
index 1cd5c63..d811e5d 100644
--- a/sandbox/mac/xpc_message_server.cc
+++ b/sandbox/mac/xpc_message_server.cc
@@ -12,17 +12,6 @@
 #include "base/strings/stringprintf.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,
@@ -30,6 +19,7 @@
     : demuxer_(demuxer),
       server_port_(server_receive_right),
       reply_message_(NULL) {
+  CHECK(InitializeXPC());
 }
 
 XPCMessageServer::~XPCMessageServer() {
@@ -78,6 +68,9 @@
 }
 
 bool XPCMessageServer::SendReply(IPCMessage reply) {
+  if (!reply.xpc)
+    return false;
+
   int rv = xpc_pipe_routine_reply(reply.xpc);
   if (rv) {
     LOG(ERROR) << "Failed to xpc_pipe_routine_reply(): " << rv;
@@ -98,8 +91,11 @@
 
 void XPCMessageServer::RejectMessage(IPCMessage request, int error_code) {
   IPCMessage reply = CreateReply(request);
-  xpc_dictionary_set_int64(reply.xpc, "error", error_code);
-  SendReply(reply);
+  // The message wasn't expecting a reply, so rejecting means ignoring it.
+  if (reply.xpc) {
+    xpc_dictionary_set_int64(reply.xpc, "error", error_code);
+    SendReply(reply);
+  }
 }
 
 mach_port_t XPCMessageServer::GetServerPort() const {
@@ -108,7 +104,7 @@
 
 void XPCMessageServer::ReceiveMessage() {
   IPCMessage request;
-  int rv = xpc_pipe_receive(server_port_, &request.xpc);
+  int rv = xpc_pipe_receive(server_port_.get(), &request.xpc);
   if (rv) {
     LOG(ERROR) << "Failed to xpc_pipe_receive(): " << rv;
     return;
diff --git a/sandbox/mac/xpc_message_server.h b/sandbox/mac/xpc_message_server.h
index 5f5a9fa..48209a6 100644
--- a/sandbox/mac/xpc_message_server.h
+++ b/sandbox/mac/xpc_message_server.h
@@ -14,18 +14,6 @@
 #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 {
 
 // An implementation of MessageServer that uses XPC pipes to read and write XPC
diff --git a/sandbox/mac/xpc_message_server_unittest.cc b/sandbox/mac/xpc_message_server_unittest.cc
index 4c4fcf9..26e4ad0 100644
--- a/sandbox/mac/xpc_message_server_unittest.cc
+++ b/sandbox/mac/xpc_message_server_unittest.cc
@@ -18,27 +18,6 @@
 #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 {
@@ -150,6 +129,20 @@
   xpc_release(reply);
 }
 
+XPC_TEST_F(RejectMessageSimpleRoutine)  // {
+  BlockDemuxer fixture;
+  XPCMessageServer* server = fixture.server();
+  ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
+      server->RejectMessage(request, -99);
+  }));
+
+  // Create a message that is not expecting a reply.
+  xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
+  EXPECT_EQ(0, xpc_pipe_simpleroutine(fixture.pipe(), request));
+
+  xpc_release(request);
+}
+
 char kGetSenderPID[] = "org.chromium.sandbox.test.GetSenderPID";
 
 XPC_TEST_F(GetSenderPID)  // {
diff --git a/sandbox/mac/xpc_private_stubs.sig b/sandbox/mac/xpc_private_stubs.sig
index 7ab2934..b8e1c50 100644
--- a/sandbox/mac/xpc_private_stubs.sig
+++ b/sandbox/mac/xpc_private_stubs.sig
@@ -10,6 +10,9 @@
 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);
 
+// Raw object getters.
+mach_port_t xpc_mach_send_get_right(xpc_object_t value);
+
 // 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);
diff --git a/sandbox/mac/xpc_stubs.sig b/sandbox/mac/xpc_stubs.sig
index d20af58..b8e7699 100644
--- a/sandbox/mac/xpc_stubs.sig
+++ b/sandbox/mac/xpc_stubs.sig
@@ -16,4 +16,5 @@
 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);
+bool xpc_dictionary_get_bool(xpc_object_t dictionary, const char* key);
 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
index 8197587..977ffe7 100644
--- a/sandbox/mac/xpc_stubs_header.fragment
+++ b/sandbox/mac/xpc_stubs_header.fragment
@@ -28,4 +28,49 @@
 typedef struct _xpc_pipe_s* xpc_pipe_t;
 }  // extern "C"
 
+#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);
+
+XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL_ALL
+bool xpc_dictionary_get_bool(xpc_object_t xdict, const char* key);
+
+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
+const char* xpc_dictionary_get_string(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_NONNULL1 XPC_NONNULL2
+void xpc_dictionary_set_string(xpc_object_t xdict, const char* key,
+                               const char* string);
+
+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);
+XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL_ALL
+    xpc_object_t
+    xpc_dictionary_create_reply(xpc_object_t original);
+
+XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL1 XPC_NONNULL2
+xpc_object_t xpc_dictionary_get_value(xpc_object_t xdict, const char* key);
+
+XPC_EXPORT XPC_MALLOC XPC_WARN_RESULT XPC_NONNULL1
+char* xpc_copy_description(xpc_object_t object);
+}  // extern "C"
+#endif
+
 #endif  // SANDBOX_MAC_XPC_STUBS_HEADER_FRAGMENT_
diff --git a/sandbox/sandbox_export.h b/sandbox/sandbox_export.h
index 40a4036..35d6a1b 100644
--- a/sandbox/sandbox_export.h
+++ b/sandbox/sandbox_export.h
@@ -13,16 +13,13 @@
 
 #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)
 
diff --git a/sandbox/sandbox_linux_unittests.isolate b/sandbox/sandbox_linux_unittests.isolate
index 2dadddd..2b7c2a7 100644
--- a/sandbox/sandbox_linux_unittests.isolate
+++ b/sandbox/sandbox_linux_unittests.isolate
@@ -12,10 +12,6 @@
         'command': [
           '<(PRODUCT_DIR)/sandbox_linux_unittests',
         ],
-        'files': [
-          '<(PRODUCT_DIR)/sandbox_linux_unittests',
-        ],
-        'read_only': 1,
       },
     }],
   ],
diff --git a/sandbox/sandbox_linux_unittests_android.isolate b/sandbox/sandbox_linux_unittests_android.isolate
new file mode 100644
index 0000000..a0a7e9e
--- /dev/null
+++ b/sandbox/sandbox_linux_unittests_android.isolate
@@ -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.
+{
+  'includes': [
+    '../build/android/android.isolate',
+    'sandbox_linux_unittests.isolate',
+  ],
+  'variables': {
+    'command': [
+      '<(PRODUCT_DIR)/bin/run_sandbox_linux_unittests',
+    ],
+    'files': [
+      '<(PRODUCT_DIR)/bin/run_sandbox_linux_unittests',
+      '<(PRODUCT_DIR)/sandbox_linux_unittests',
+    ]
+  },
+}
diff --git a/sandbox/sandbox_mac_unittests.isolate b/sandbox/sandbox_mac_unittests.isolate
new file mode 100644
index 0000000..a202a9b
--- /dev/null
+++ b/sandbox/sandbox_mac_unittests.isolate
@@ -0,0 +1,9 @@
+# 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.
+{
+  'variables': {
+    'command': [ '<(PRODUCT_DIR)/sandbox_mac_unittests' ],
+  },
+  'includes': [ '../base/base.isolate' ],
+}
diff --git a/sandbox/sandbox_nacl_nonsfi.gyp b/sandbox/sandbox_nacl_nonsfi.gyp
deleted file mode 100644
index f56ad15..0000000
--- a/sandbox/sandbox_nacl_nonsfi.gyp
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright 2015 The Chromium 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',
-          ],
-        },
-
-        {
-          'target_name': 'sandbox_linux_test_utils_nacl_nonsfi',
-          'type': 'none',
-          'variables': {
-            'nacl_untrusted_build': 1,
-            'nlib_target': 'libsandbox_linux_test_utils_nacl_nonsfi.a',
-            'build_glibc': 0,
-            'build_newlib': 0,
-            'build_irt': 0,
-            'build_pnacl_newlib': 0,
-            'build_nonsfi_helper': 1,
-
-            'sources': [
-              'linux/seccomp-bpf/sandbox_bpf_test_runner.cc',
-              'linux/tests/sandbox_test_runner.cc',
-              'linux/tests/unit_tests.cc',
-            ],
-          },
-          'dependencies': [
-            '../testing/gtest_nacl.gyp:gtest_nacl',
-          ],
-        },
-      ],
-    }],
-  ],
-}
diff --git a/sandbox/sbox_integration_tests.isolate b/sandbox/sbox_integration_tests.isolate
new file mode 100644
index 0000000..719cd38
--- /dev/null
+++ b/sandbox/sbox_integration_tests.isolate
@@ -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.
+
+# Because of a limitation in isolate_driver.py, this file needs to be in
+# the same directory as the main .gyp file.
+
+{
+  'conditions': [
+    ['OS=="win"', {
+      'variables': {
+        'command': [
+          '<(PRODUCT_DIR)/sbox_integration_tests.exe',
+        ],
+      },
+    }],
+    ['OS=="win" and target_arch=="ia32"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/wow_helper.exe',
+        ],
+      },
+    }],
+    # These PDBs are needed in order to get reasonable stack traces if
+    # an assertion fires or a crash occurs. Add more as necessary.
+    ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/sbox_integration_tests.exe.pdb',
+        ],
+      },
+    }],
+  ],
+  'includes': [
+    '../base/base.isolate',
+  ],
+}
diff --git a/sandbox/sbox_unittests.isolate b/sandbox/sbox_unittests.isolate
new file mode 100644
index 0000000..e6dec25
--- /dev/null
+++ b/sandbox/sbox_unittests.isolate
@@ -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.
+
+# Because of a limitation in isolate_driver.py, this file needs to be in
+# the same directory as the main .gyp file.
+
+{
+  'conditions': [
+    ['OS=="win"', {
+      'variables': {
+        'command': [
+          '<(PRODUCT_DIR)/sbox_unittests.exe',
+        ],
+      },
+    }],
+    ['OS=="win" and target_arch=="ia32"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/wow_helper.exe',
+        ],
+      },
+    }],
+  ],
+  'includes': [
+    '../base/base.isolate',
+  ],
+}
diff --git a/sandbox/sbox_validation_tests.isolate b/sandbox/sbox_validation_tests.isolate
new file mode 100644
index 0000000..4daee6b
--- /dev/null
+++ b/sandbox/sbox_validation_tests.isolate
@@ -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.
+
+# Because of a limitation in isolate_driver.py, this file needs to be in
+# the same directory as the main .gyp file.
+
+{
+  'conditions': [
+    ['OS=="win"', {
+      'variables': {
+        'command': [
+          '<(PRODUCT_DIR)/sbox_validation_tests.exe',
+        ],
+      },
+    }],
+    ['OS=="win" and target_arch=="ia32"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/wow_helper.exe',
+        ],
+      },
+    }],
+  ],
+  'includes': [
+    '../base/base.isolate',
+  ],
+}
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 3063f7f..129f065 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -34,8 +34,6 @@
     "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",
@@ -101,14 +99,14 @@
     "src/sandbox_policy.h",
     "src/sandbox_policy_base.cc",
     "src/sandbox_policy_base.h",
+    "src/sandbox_rand.cc",
+    "src/sandbox_rand.h",
     "src/sandbox_types.h",
     "src/sandbox_utils.cc",
     "src/sandbox_utils.h",
     "src/security_level.h",
     "src/service_resolver.cc",
     "src/service_resolver.h",
-    "src/shared_handles.cc",
-    "src/shared_handles.h",
     "src/sharedmem_ipc_client.cc",
     "src/sharedmem_ipc_client.h",
     "src/sharedmem_ipc_server.cc",
@@ -161,6 +159,8 @@
     ]
   }
 
+  configs += [ "//build/config:precompiled_headers" ]
+
   deps = [
     "//base",
     "//base:base_static",
@@ -246,6 +246,7 @@
     "src/policy_low_level_unittest.cc",
     "src/policy_opcodes_unittest.cc",
     "src/restricted_token_unittest.cc",
+    "src/sandbox_nt_util_unittest.cc",
     "src/service_resolver_unittest.cc",
     "src/sid_unittest.cc",
     "src/threadpool_unittest.cc",
@@ -279,8 +280,8 @@
   libs = [ "comctl32.lib" ]
 
   deps = [
-    ":sandbox",
     ":pocdll",
+    ":sandbox",
   ]
 }
 
@@ -299,4 +300,8 @@
   ]
 
   defines = [ "POCDLL_EXPORTS" ]
+
+  deps = [
+    "//build/config/sanitizers:deps",
+  ]
 }
diff --git a/sandbox/win/OWNERS b/sandbox/win/OWNERS
index 9ccaeb3..85047f7 100644
--- a/sandbox/win/OWNERS
+++ b/sandbox/win/OWNERS
@@ -1,3 +1,3 @@
 cpu@chromium.org
 jschuh@chromium.org
-rvargas@chromium.org
+wfh@chromium.org
diff --git a/sandbox/win/sandbox_poc/main_ui_window.cc b/sandbox/win/sandbox_poc/main_ui_window.cc
index 1671424..8d67cec 100644
--- a/sandbox/win/sandbox_poc/main_ui_window.cc
+++ b/sandbox/win/sandbox_poc/main_ui_window.cc
@@ -5,6 +5,7 @@
 #include <windows.h>
 #include <CommCtrl.h>
 #include <commdlg.h>
+#include <stdarg.h>
 #include <time.h>
 #include <windowsx.h>
 #include <atlbase.h>
@@ -26,11 +27,11 @@
 const wchar_t MainUIWindow::kDefaultLogFile_[]    = L"";
 
 MainUIWindow::MainUIWindow()
-    : instance_handle_(NULL),
+    : broker_(NULL),
       spawn_target_(L""),
+      instance_handle_(NULL),
       dll_path_(L""),
-      entry_point_(L""),
-      broker_(NULL) {
+      entry_point_(L"") {
 }
 
 MainUIWindow::~MainUIWindow() {
@@ -162,8 +163,6 @@
                                                   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);
@@ -258,7 +257,7 @@
     return FALSE;
 
   LVCOLUMN list_view_column = {0};
-  list_view_column.mask = LVCF_FMT | LVCF_WIDTH ;
+  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);
@@ -272,17 +271,12 @@
 }
 
 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_) {
@@ -413,9 +407,8 @@
   ATL::CStringA string_to_print;
 
   DWORD last_error = 0;
-  while(last_error == ERROR_SUCCESS || last_error == ERROR_PIPE_LISTENING ||
-        last_error == ERROR_NO_DATA)
-  {
+  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,
@@ -532,7 +525,6 @@
         spawn_target_.c_str(), arguments, result);
     return_value = false;
   } else {
-
     DWORD thread_id;
     ::CreateThread(NULL,  // Default security attributes
                    NULL,  // Default stack size
@@ -624,7 +616,7 @@
   const int kMaxDebugBuffSize = 1024;
 
   va_list arg_list;
-  _crt_va_start(arg_list, format);
+  va_start(arg_list, format);
 
   wchar_t text[kMaxDebugBuffSize + 1];
   vswprintf_s(text, kMaxDebugBuffSize, format, arg_list);
diff --git a/sandbox/win/sandbox_poc/pocdll/handles.cc b/sandbox/win/sandbox_poc/pocdll/handles.cc
index a12d433..1c6116e 100644
--- a/sandbox/win/sandbox_poc/pocdll/handles.cc
+++ b/sandbox/win/sandbox_poc/pocdll/handles.cc
@@ -120,7 +120,7 @@
       // 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};
+      IO_STATUS_BLOCK status_block = {};
       do {
         // Delete the previous buffer create. The buffer was too small
         if (file_name) {
diff --git a/sandbox/win/sandbox_poc/pocdll/invasive.cc b/sandbox/win/sandbox_poc/pocdll/invasive.cc
index 9ee13b0..954526d 100644
--- a/sandbox/win/sandbox_poc/pocdll/invasive.cc
+++ b/sandbox/win/sandbox_poc/pocdll/invasive.cc
@@ -13,15 +13,14 @@
 // 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);
+DWORD WINAPI MyThreadBombimgFunction(void* param) {
   Sleep(INFINITE);
   return 0;
 }
 
 void POCDLL_API TestThreadBombing(HANDLE log) {
   HandleToFile handle2file;
-  FILE *output = handle2file.Translate(log, "w");
+  FILE* output = handle2file.Translate(log, "w");
 
   // we stop after 5 errors in a row
   int number_errors = 0;
@@ -55,8 +54,7 @@
 // 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);
+DWORD WINAPI TakeAllCpu(void* param) {
   int cpt = 0;
   for (;;) {
     cpt += 2;
@@ -69,7 +67,7 @@
 
 void POCDLL_API TestTakeAllCpu(HANDLE log) {
   HandleToFile handle2file;
-  FILE *output = handle2file.Translate(log, "w");
+  FILE* output = handle2file.Translate(log, "w");
 
   DWORD_PTR process_mask = 0;
   DWORD_PTR system_mask = 0;
@@ -110,14 +108,14 @@
 
 void POCDLL_API TestUseAllMemory(HANDLE log) {
   HandleToFile handle2file;
-  FILE *output = handle2file.Translate(log, "w");
+  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));
+    DWORD* ptr_to_leak = reinterpret_cast<DWORD*>(malloc(1024 * 256));
     if (ptr_to_leak) {
-      memory_size += (256);
+      memory_size += 256;
       number_errors = 0;
     } else {
       number_errors++;
@@ -135,7 +133,7 @@
 
 void POCDLL_API TestCreateObjects(HANDLE log) {
   HandleToFile handle2file;
-  FILE *output = handle2file.Translate(log, "w");
+  FILE* output = handle2file.Translate(log, "w");
 
   int mutexes = 0;
   int jobs = 0;
@@ -187,7 +185,7 @@
 // "output" is the stream used for logging.
 void POCDLL_API TestCloseHWND(HANDLE log) {
   HandleToFile handle2file;
-  FILE *output = handle2file.Translate(log, "w");
+  FILE* output = handle2file.Translate(log, "w");
 
   ::EnumWindows(EnumWindowCallback, PtrToLong(output));
   // TODO(nsylvain): find a way to know when the enum is finished
diff --git a/sandbox/win/sandbox_poc/pocdll/pocdll.cc b/sandbox/win/sandbox_poc/pocdll/pocdll.cc
index e058f58..c6c5453 100644
--- a/sandbox/win/sandbox_poc/pocdll/pocdll.cc
+++ b/sandbox/win/sandbox_poc/pocdll/pocdll.cc
@@ -6,12 +6,7 @@
 #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);
+BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
   return TRUE;
 }
 
diff --git a/sandbox/win/sandbox_poc/sandbox.cc b/sandbox/win/sandbox_poc/sandbox.cc
index e282075..88757ef 100644
--- a/sandbox/win/sandbox_poc/sandbox.cc
+++ b/sandbox/win/sandbox_poc/sandbox.cc
@@ -2,10 +2,14 @@
 // 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/sandbox.h"
+
 #include <windows.h>
 #include <tchar.h>
 #include <shellapi.h>
-#include "sandbox/win/sandbox_poc/sandbox.h"
+
+#include <string>
+
 #include "base/logging.h"
 #include "sandbox/win/sandbox_poc/main_ui_window.h"
 #include "sandbox/win/src/sandbox.h"
@@ -24,7 +28,7 @@
   if (!dll_name || !entry_point || !log_file)
     return false;
 
-  LPWSTR *arg_list;
+  LPWSTR* arg_list;
   int arg_count;
 
   // We expect the command line to contain: EntryPointName "DLLPath" "LogPath"
@@ -49,8 +53,6 @@
 
 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;
@@ -168,7 +170,7 @@
       return -6;
     }
 
-   // Transfer control to the entry point in the DLL requested
+    // Transfer control to the entry point in the DLL requested
     init_function(pipe);
 
     CloseHandle(pipe);
diff --git a/sandbox/win/sandbox_win.gypi b/sandbox/win/sandbox_win.gypi
index e085cfb..08d512a 100644
--- a/sandbox/win/sandbox_win.gypi
+++ b/sandbox/win/sandbox_win.gypi
@@ -41,8 +41,6 @@
             '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',
@@ -106,6 +104,8 @@
             'src/sandbox_policy_base.cc',
             'src/sandbox_policy_base.h',
             'src/sandbox_policy.h',
+            'src/sandbox_rand.cc',
+            'src/sandbox_rand.h',
             'src/sandbox_types.h',
             'src/sandbox_utils.cc',
             'src/sandbox_utils.h',
@@ -114,8 +114,6 @@
             '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',
@@ -189,12 +187,6 @@
       'include_dirs': [
         '../..',
       ],
-      'direct_dependent_settings': {
-        'include_dirs': [
-          'src',
-          '../..',
-        ],
-      },
       'target_conditions': [
         ['target_arch=="ia32"', {
           'copies': [
@@ -278,6 +270,7 @@
         'src/policy_low_level_unittest.cc',
         'src/policy_opcodes_unittest.cc',
         'src/ipc_unittest.cc',
+        'src/sandbox_nt_util_unittest.cc',
         'src/threadpool_unittest.cc',
         'src/win_utils_unittest.cc',
         'tests/common/test_utils.cc',
@@ -357,17 +350,54 @@
           'include_dirs': [
             '../..',
           ],
-          'direct_dependent_settings': {
-            'include_dirs': [
-              'src',
-              '../..',
-            ],
-          },
           'defines': [
             '<@(nacl_win64_defines)',
           ]
         },
       ],
     }],
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'sbox_integration_tests_run',
+          'type': 'none',
+          'dependencies': [
+            'sbox_integration_tests',
+          ],
+          'includes': [
+            '../../build/isolate.gypi',
+          ],
+          'sources': [
+            '../sbox_integration_tests.isolate',
+          ],
+        },
+        {
+          'target_name': 'sbox_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'sbox_unittests',
+          ],
+          'includes': [
+            '../../build/isolate.gypi',
+          ],
+          'sources': [
+            '../sbox_unittests.isolate',
+          ],
+        },
+        {
+          'target_name': 'sbox_validation_tests_run',
+          'type': 'none',
+          'dependencies': [
+            'sbox_validation_tests',
+          ],
+          'includes': [
+            '../../build/isolate.gypi',
+          ],
+          'sources': [
+            '../sbox_validation_tests.isolate',
+          ],
+        },
+      ],
+    }],
   ],
 }
diff --git a/sandbox/win/src/Wow64.cc b/sandbox/win/src/Wow64.cc
index 60ee13d..24facfc 100644
--- a/sandbox/win/src/Wow64.cc
+++ b/sandbox/win/src/Wow64.cc
@@ -73,12 +73,11 @@
 
 namespace sandbox {
 
-Wow64::~Wow64() {
-  if (dll_load_)
-    ::CloseHandle(dll_load_);
+Wow64::Wow64(TargetProcess* child, HMODULE ntdll)
+    : child_(child), ntdll_(ntdll), dll_load_(NULL), continue_load_(NULL) {
+}
 
-  if (continue_load_)
-    ::CloseHandle(continue_load_);
+Wow64::~Wow64() {
 }
 
 // The basic idea is to allocate one page of memory on the child, and initialize
@@ -96,17 +95,20 @@
   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);
+  dll_load_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+  continue_load_.Set(::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))
+  if (!::DuplicateHandle(current_process, dll_load_.Get(), child_->Process(),
+                         &remote_load, access, FALSE, 0)) {
     return false;
-  if (!::DuplicateHandle(current_process, continue_load_, child_->Process(),
-                         &remote_continue, access, FALSE, 0))
+  }
+  if (!::DuplicateHandle(current_process, continue_load_.Get(),
+                         child_->Process(), &remote_continue, access, FALSE,
+                         0)) {
     return false;
+  }
 
   void* buffer = ::VirtualAllocEx(child_->Process(), NULL, page_size,
                                   MEM_COMMIT, PAGE_EXECUTE_READWRITE);
@@ -185,11 +187,11 @@
   }
 
   for (;;) {
-    DWORD reason = ::WaitForSingleObject(dll_load_, INFINITE);
+    DWORD reason = ::WaitForSingleObject(dll_load_.Get(), INFINITE);
     if (WAIT_TIMEOUT == reason || WAIT_ABANDONED == reason)
       return false;
 
-    if (!::ResetEvent(dll_load_))
+    if (!::ResetEvent(dll_load_.Get()))
       return false;
 
     bool found = NtdllPresent();
@@ -198,7 +200,7 @@
         return false;
     }
 
-    if (!::SetEvent(continue_load_))
+    if (!::SetEvent(continue_load_.Get()))
       return false;
 
     if (found)
diff --git a/sandbox/win/src/Wow64.h b/sandbox/win/src/Wow64.h
index e9bbd53..5858ed8 100644
--- a/sandbox/win/src/Wow64.h
+++ b/sandbox/win/src/Wow64.h
@@ -8,6 +8,7 @@
 #include <windows.h>
 
 #include "base/basictypes.h"
+#include "base/win/scoped_handle.h"
 #include "sandbox/win/src/sandbox_types.h"
 
 namespace sandbox {
@@ -18,8 +19,7 @@
 // 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(TargetProcess* child, HMODULE ntdll);
   ~Wow64();
 
   // Waits for the 32 bit DLL to get loaded on the child process. This function
@@ -40,8 +40,10 @@
 
   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.
+  // Event that is signaled on dll load.
+  base::win::ScopedHandle dll_load_;
+  // Event to signal to continue execution on the child.
+  base::win::ScopedHandle continue_load_;
   DISALLOW_IMPLICIT_CONSTRUCTORS(Wow64);
 };
 
diff --git a/sandbox/win/src/Wow64_64.cc b/sandbox/win/src/Wow64_64.cc
index f03831b..357deb8 100644
--- a/sandbox/win/src/Wow64_64.cc
+++ b/sandbox/win/src/Wow64_64.cc
@@ -8,6 +8,10 @@
 
 namespace sandbox {
 
+Wow64::Wow64(TargetProcess* child, HMODULE ntdll)
+    : child_(child), ntdll_(ntdll), dll_load_(NULL), continue_load_(NULL) {
+}
+
 Wow64::~Wow64() {
 }
 
diff --git a/sandbox/win/src/app_container.h b/sandbox/win/src/app_container.h
index 8125d70..a08c01b 100644
--- a/sandbox/win/src/app_container.h
+++ b/sandbox/win/src/app_container.h
@@ -56,7 +56,7 @@
 ResultCode CreateAppContainer(const base::string16& sid,
                               const base::string16& name);
 
-// Deletes an AppContainer previously created with a successfull call to
+// Deletes an AppContainer previously created with a successful call to
 // CreateAppContainer.
 ResultCode DeleteAppContainer(const base::string16& sid);
 
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc
index fec98f9..5e6494f 100644
--- a/sandbox/win/src/broker_services.cc
+++ b/sandbox/win/src/broker_services.cc
@@ -7,7 +7,9 @@
 #include <AclAPI.h>
 
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
 #include "base/threading/platform_thread.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/scoped_process_information.h"
@@ -55,22 +57,47 @@
 // 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) {
+  JobTracker(base::win::ScopedHandle job, sandbox::PolicyBase* policy)
+      : job(job.Pass()), policy(policy) {
   }
+  ~JobTracker() {
+    FreeResources();
+  }
+
+  // Releases the Job and notifies the associated Policy object to release its
+  // resources as well.
+  void FreeResources();
+
+  base::win::ScopedHandle job;
+  sandbox::PolicyBase* policy;
 };
 
+void JobTracker::FreeResources() {
+  if (policy) {
+    BOOL res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK);
+    DCHECK(res);
+    // Closing the job causes the target process to be destroyed so this needs
+    // to happen before calling OnJobEmpty().
+    HANDLE stale_job_handle = job.Get();
+    job.Close();
+
+    // In OnJobEmpty() we don't actually use the job handle directly.
+    policy->OnJobEmpty(stale_job_handle);
+    policy->Release();
+    policy = NULL;
+  }
+}
+
 // Helper structure that allows the broker to track peer processes
 struct PeerTracker {
+  PeerTracker(DWORD process_id, HANDLE broker_job_port)
+      : wait_object(NULL), id(process_id), job_port(broker_job_port) {
+  }
+
   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) {
@@ -82,70 +109,30 @@
   }
 }
 
-// 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) {
+BrokerServicesBase::BrokerServicesBase() : thread_pool_(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_))
+  if (job_port_.IsValid() || (NULL != thread_pool_))
     return SBOX_ERROR_UNEXPECTED_CALL;
 
   ::InitializeCriticalSection(&lock_);
 
-  job_port_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
-  if (NULL == job_port_)
+  job_port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0));
+  if (!job_port_.IsValid())
     return SBOX_ERROR_GENERIC;
 
-  no_targets_ = ::CreateEventW(NULL, TRUE, FALSE, NULL);
+  no_targets_.Set(::CreateEventW(NULL, TRUE, FALSE, NULL));
 
-  job_thread_ = ::CreateThread(NULL, 0,  // Default security and stack.
-                               TargetEventsThread, this, NULL, NULL);
-  if (NULL == job_thread_)
+  job_thread_.Set(::CreateThread(NULL, 0,  // Default security and stack.
+                                 TargetEventsThread, this, NULL, NULL));
+  if (!job_thread_.IsValid())
     return SBOX_ERROR_GENERIC;
 
   return SBOX_ALL_OK;
@@ -158,31 +145,24 @@
 // wait for threads here.
 BrokerServicesBase::~BrokerServicesBase() {
   // If there is no port Init() was never called successfully.
-  if (!job_port_)
+  if (!job_port_.IsValid())
     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_);
+  ::PostQueuedCompletionStatus(job_port_.Get(), 0, THREAD_CTRL_QUIT, FALSE);
 
-  if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) {
+  if (job_thread_.IsValid() &&
+      WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_.Get(), 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_);
+  STLDeleteElements(&tracker_list_);
   delete thread_pool_;
-  ::CloseHandle(no_targets_);
 
   // Cancel the wait events and delete remaining peer trackers.
   for (PeerTrackerMap::iterator it = peer_map_.begin();
@@ -190,16 +170,7 @@
     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);
-  }
+  ::DeleteCriticalSection(&lock_);
 }
 
 TargetPolicy* BrokerServicesBase::CreatePolicy() {
@@ -208,21 +179,6 @@
   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
@@ -234,8 +190,8 @@
   base::PlatformThread::SetName("BrokerEvent");
 
   BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param);
-  HANDLE port = broker->job_port_;
-  HANDLE no_targets = broker->no_targets_;
+  HANDLE port = broker->job_port_.Get();
+  HANDLE no_targets = broker->no_targets_.Get();
 
   int target_counter = 0;
   ::ResetEvent(no_targets);
@@ -245,11 +201,12 @@
     ULONG_PTR key = 0;
     LPOVERLAPPED ovl = NULL;
 
-    if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE))
+    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
@@ -263,7 +220,7 @@
           // 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);
+          tracker->FreeResources();
           break;
         }
 
@@ -295,7 +252,7 @@
         }
 
         case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: {
-          BOOL res = ::TerminateJobObject(tracker->job,
+          BOOL res = ::TerminateJobObject(tracker->job.Get(),
                                           SBOX_FATAL_MEMORY_EXCEEDED);
           DCHECK(res);
           break;
@@ -355,53 +312,20 @@
 
   // 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;
+  base::win::ScopedHandle initial_token;
+  base::win::ScopedHandle lockdown_token;
+  base::win::ScopedHandle lowbox_token;
   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);
+  result =
+      policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token);
   if (SBOX_ALL_OK != result)
     return result;
 
-  base::win::ScopedHandle job(job_temp);
+  base::win::ScopedHandle job;
+  result = policy_base->MakeJobObject(&job);
+  if (SBOX_ALL_OK != result)
+    return result;
 
   // Initialize the startup information from the policy.
   base::win::StartupInformation startup_info;
@@ -444,10 +368,10 @@
     if (stderr_handle != stdout_handle && stderr_handle != INVALID_HANDLE_VALUE)
       inherited_handle_list.push_back(stderr_handle);
 
-    HandleList policy_handle_list = policy_base->GetHandlesBeingShared();
+    const HandleList& policy_handle_list = policy_base->GetHandlesBeingShared();
 
     for (auto handle : policy_handle_list)
-      inherited_handle_list.push_back(handle);
+      inherited_handle_list.push_back(handle->Get());
 
     if (inherited_handle_list.size())
       ++attribute_count;
@@ -494,13 +418,11 @@
   // 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_);
+  TargetProcess* target =
+      new TargetProcess(initial_token.Pass(), lockdown_token.Pass(),
+                        lowbox_token.Pass(), 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();
@@ -519,9 +441,13 @@
   // 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);
+    scoped_ptr<JobTracker> tracker(new JobTracker(job.Pass(), policy_base));
+
+    // There is no obvious recovery after failure here. Previous version with
+    // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639
+    CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(),
+                                  tracker.get()));
+
     // Save the tracker because in cleanup we might need to force closing
     // the Jobs.
     tracker_list_.push_back(tracker.release());
@@ -531,10 +457,13 @@
     // 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_);
+      ::SetEvent(no_targets_.Get());
     // 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.
+    // Sandbox policy engine needs to know that these processes are valid
+    // targets for e.g. BrokerDuplicateHandle so track them as peer processes.
+    AddTargetPeer(process_info.process_handle());
   }
 
   *target_info = process_info.Take();
@@ -543,7 +472,7 @@
 
 
 ResultCode BrokerServicesBase::WaitForAllTargets() {
-  ::WaitForSingleObject(no_targets_, INFINITE);
+  ::WaitForSingleObject(no_targets_.Get(), INFINITE);
   return SBOX_ALL_OK;
 }
 
@@ -563,7 +492,7 @@
 
 ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) {
   scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process),
-                                               job_port_));
+                                               job_port_.Get()));
   if (!peer->id)
     return SBOX_ERROR_GENERIC;
 
@@ -587,7 +516,7 @@
   }
 
   // Release the pointer since it will be cleaned up by the callback.
-  peer.release();
+  ignore_result(peer.release());
   return SBOX_ALL_OK;
 }
 
diff --git a/sandbox/win/src/broker_services.h b/sandbox/win/src/broker_services.h
index 3e7a179..b16d5fc 100644
--- a/sandbox/win/src/broker_services.h
+++ b/sandbox/win/src/broker_services.h
@@ -64,9 +64,8 @@
   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);
+  typedef std::list<JobTracker*> JobTrackerList;
+  typedef std::map<DWORD, PeerTracker*> PeerTrackerMap;
 
   // The routine that the worker thread executes. It is in charge of
   // notifications and cleanup-related tasks.
@@ -77,14 +76,14 @@
 
   // The completion port used by the job objects to communicate events to
   // the worker thread.
-  HANDLE job_port_;
+  base::win::ScopedHandle job_port_;
 
   // Handle to a manual-reset event that is signaled when the total target
   // process count reaches zero.
-  HANDLE no_targets_;
+  base::win::ScopedHandle no_targets_;
 
   // Handle to the worker thread that reacts to job notifications.
-  HANDLE job_thread_;
+  base::win::ScopedHandle job_thread_;
 
   // Lock used to protect the list of targets from being modified by 2
   // threads at the same time.
@@ -94,21 +93,16 @@
   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);
 };
 
diff --git a/sandbox/win/src/crosscall_params.h b/sandbox/win/src/crosscall_params.h
index 6facb20..7adb918 100644
--- a/sandbox/win/src/crosscall_params.h
+++ b/sandbox/win/src/crosscall_params.h
@@ -14,16 +14,13 @@
 #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) {
+inline 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
@@ -143,10 +140,7 @@
  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) {
-  }
+      : tag_(tag), is_in_out_(0), params_count_(params_count) {}
 
  private:
   uint32 tag_;
diff --git a/sandbox/win/src/crosscall_server.h b/sandbox/win/src/crosscall_server.h
index 41888c1..824b63e 100644
--- a/sandbox/win/src/crosscall_server.h
+++ b/sandbox/win/src/crosscall_server.h
@@ -143,7 +143,6 @@
 // process handle and the job object handle that contains the client process.
 struct ClientInfo {
   HANDLE process;
-  HANDLE job_object;
   DWORD process_id;
 };
 
diff --git a/sandbox/win/src/file_policy_test.cc b/sandbox/win/src/file_policy_test.cc
index 8b52362..f7509bd 100644
--- a/sandbox/win/src/file_policy_test.cc
+++ b/sandbox/win/src/file_policy_test.cc
@@ -74,7 +74,7 @@
 
 SBOX_TESTS_COMMAND int File_Win32Create(int argc, wchar_t **argv) {
   if (argc != 1) {
-    SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   }
 
   base::string16 full_path = MakePathToSys(argv[0], false);
@@ -116,12 +116,12 @@
   UNICODE_STRING object_name;
   RtlInitUnicodeString(&object_name, file.c_str());
 
-  OBJECT_ATTRIBUTES obj_attributes = {0};
+  OBJECT_ATTRIBUTES obj_attributes = {};
   InitializeObjectAttributes(&obj_attributes, &object_name,
                              OBJ_CASE_INSENSITIVE, NULL, NULL);
 
   HANDLE handle;
-  IO_STATUS_BLOCK io_block = {0};
+  IO_STATUS_BLOCK io_block = {};
   NTSTATUS status = NtCreateFile(&handle, FILE_READ_DATA, &obj_attributes,
                                  &io_block, NULL, 0, kSharing, FILE_OPEN,
                                  0, NULL, 0);
@@ -151,12 +151,12 @@
   UNICODE_STRING object_name;
   RtlInitUnicodeString(&object_name, file.c_str());
 
-  OBJECT_ATTRIBUTES obj_attributes = {0};
+  OBJECT_ATTRIBUTES obj_attributes = {};
   InitializeObjectAttributes(&obj_attributes, &object_name,
                              OBJ_CASE_INSENSITIVE, NULL, NULL);
 
   HANDLE handle;
-  IO_STATUS_BLOCK io_block = {0};
+  IO_STATUS_BLOCK io_block = {};
   NTSTATUS status = NtOpenFile(&handle, FILE_READ_DATA, &obj_attributes,
                                &io_block, kSharing, 0);
   if (NT_SUCCESS(status)) {
@@ -175,9 +175,9 @@
   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};
+  ULARGE_INTEGER free_user = {};
+  ULARGE_INTEGER total = {};
+  ULARGE_INTEGER free_total = {};
   if (::GetDiskFreeSpaceExW(sys_path.c_str(), &free_user, &total,
                             &free_total)) {
     if ((total.QuadPart != 0) && (free_total.QuadPart !=0)) {
@@ -230,12 +230,12 @@
   base::string16 file = MakePathToSys(argv[0], true);
   RtlInitUnicodeString(&object_name, file.c_str());
 
-  OBJECT_ATTRIBUTES obj_attributes = {0};
+  OBJECT_ATTRIBUTES obj_attributes = {};
   InitializeObjectAttributes(&obj_attributes, &object_name,
                              OBJ_CASE_INSENSITIVE, NULL, NULL);
 
-  FILE_BASIC_INFORMATION info = {0};
-  FILE_NETWORK_OPEN_INFORMATION full_info = {0};
+  FILE_BASIC_INFORMATION info = {};
+  FILE_NETWORK_OPEN_INFORMATION full_info = {};
   NTSTATUS status1 = NtQueryAttributesFile(&obj_attributes, &info);
   NTSTATUS status2 = NtQueryFullAttributesFile(&obj_attributes, &full_info);
 
@@ -310,12 +310,12 @@
   EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY,
                                temp_file_name));
 
-  wchar_t command_read[MAX_PATH + 20] = {0};
+  wchar_t command_read[MAX_PATH + 20] = {};
   wsprintf(command_read, L"File_Create Read \"%ls\"", temp_file_name);
-  wchar_t command_read_create[MAX_PATH + 20] = {0};
+  wchar_t command_read_create[MAX_PATH + 20] = {};
   wsprintf(command_read_create, L"File_Create ReadCreate \"%ls\"",
            temp_file_name);
-  wchar_t command_write[MAX_PATH + 20] = {0};
+  wchar_t command_write[MAX_PATH + 20] = {};
   wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name);
 
   // Verify that we cannot create the file after revert.
@@ -346,12 +346,12 @@
   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));
+  std::wstring path(temp_file_name);
+  EXPECT_TRUE(ConvertToLongPath(&path));
   EXPECT_TRUE(GetNtPathFromWin32Path(path, &path));
   path = path.substr(sandbox::kNTDevicePrefixLen);
 
-  wchar_t command[MAX_PATH + 20] = {0};
+  wchar_t command[MAX_PATH + 20] = {};
   wsprintf(command, L"File_Create Read \"\\\\.\\%ls\"", path.c_str());
   path = std::wstring(kNTPrefix) + path;
 
@@ -374,7 +374,7 @@
   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};
+  wchar_t command_write[MAX_PATH + 20] = {};
   wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name);
 
   // Verify that we have write access after revert.
@@ -494,8 +494,7 @@
   ::DeleteFile(temp_file_name6);
   ::DeleteFile(temp_file_name8);
 
-
-  wchar_t command[MAX_PATH*2 + 20] = {0};
+  wchar_t command[MAX_PATH * 2 + 20] = {};
   wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name1,
            temp_file_name2);
   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command));
diff --git a/sandbox/win/src/filesystem_dispatcher.cc b/sandbox/win/src/filesystem_dispatcher.cc
index 4561be4..d4ef796 100644
--- a/sandbox/win/src/filesystem_dispatcher.cc
+++ b/sandbox/win/src/filesystem_dispatcher.cc
@@ -20,35 +20,37 @@
 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)
-  };
+      {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)
-  };
+      {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)
-  };
+      {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)
-  };
+      {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_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);
@@ -90,7 +92,7 @@
                                         uint32 share_access,
                                         uint32 create_disposition,
                                         uint32 create_options) {
-  if (!PreProcessName(*name, name)) {
+  if (!PreProcessName(name)) {
     // The path requested might contain a reparse point.
     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
     return true;
@@ -136,7 +138,7 @@
                                       uint32 desired_access,
                                       uint32 share_access,
                                       uint32 open_options) {
-  if (!PreProcessName(*name, name)) {
+  if (!PreProcessName(name)) {
     // The path requested might contain a reparse point.
     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
     return true;
@@ -182,7 +184,7 @@
   if (sizeof(FILE_BASIC_INFORMATION) != info->Size())
     return false;
 
-  if (!PreProcessName(*name, name)) {
+  if (!PreProcessName(name)) {
     // The path requested might contain a reparse point.
     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
     return true;
@@ -222,7 +224,7 @@
   if (sizeof(FILE_NETWORK_OPEN_INFORMATION) != info->Size())
     return false;
 
-  if (!PreProcessName(*name, name)) {
+  if (!PreProcessName(name)) {
     // The path requested might contain a reparse point.
     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
     return true;
@@ -277,7 +279,7 @@
   base::string16 name;
   name.assign(rename_info->FileName, rename_info->FileNameLength /
                                      sizeof(rename_info->FileName[0]));
-  if (!PreProcessName(name, &name)) {
+  if (!PreProcessName(&name)) {
     // The path requested might contain a reparse point.
     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
     return true;
diff --git a/sandbox/win/src/filesystem_policy.cc b/sandbox/win/src/filesystem_policy.cc
index 0349ff3..eb6b197 100644
--- a/sandbox/win/src/filesystem_policy.cc
+++ b/sandbox/win/src/filesystem_policy.cc
@@ -79,7 +79,7 @@
     return false;
   }
 
-  if (!PreProcessName(mod_name, &mod_name)) {
+  if (!PreProcessName(&mod_name)) {
     // The path to be added might contain a reparse point.
     NOTREACHED();
     return false;
@@ -255,9 +255,9 @@
     *nt_status = STATUS_ACCESS_DENIED;
     return false;
   }
-  IO_STATUS_BLOCK io_block = {0};
-  UNICODE_STRING uni_name = {0};
-  OBJECT_ATTRIBUTES obj_attributes = {0};
+  IO_STATUS_BLOCK io_block = {};
+  UNICODE_STRING uni_name = {};
+  OBJECT_ATTRIBUTES obj_attributes = {};
   SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
 
   InitObjectAttribs(file, attributes, NULL, &obj_attributes,
@@ -289,9 +289,9 @@
   }
   // 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};
+  IO_STATUS_BLOCK io_block = {};
+  UNICODE_STRING uni_name = {};
+  OBJECT_ATTRIBUTES obj_attributes = {};
   SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
 
   InitObjectAttribs(file, attributes, NULL, &obj_attributes,
@@ -394,15 +394,14 @@
   return true;
 }
 
-bool PreProcessName(const base::string16& path, base::string16* new_path) {
-  ConvertToLongPath(path, new_path);
+bool PreProcessName(base::string16* path) {
+  ConvertToLongPath(path);
 
-  bool reparsed = false;
-  if (ERROR_SUCCESS != IsReparsePoint(*new_path, &reparsed))
-    return false;
+  if (ERROR_NOT_A_REPARSE_POINT == IsReparsePoint(*path))
+    return true;
 
-  // We can't process reparsed file.
-  return !reparsed;
+  // We can't process a reparsed file.
+  return false;
 }
 
 base::string16 FixNTPrefixForMatch(const base::string16& name) {
diff --git a/sandbox/win/src/filesystem_policy.h b/sandbox/win/src/filesystem_policy.h
index ce28344..4103ad6 100644
--- a/sandbox/win/src/filesystem_policy.h
+++ b/sandbox/win/src/filesystem_policy.h
@@ -98,10 +98,9 @@
                                        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);
+// Expands the path and check if it's a reparse point. Returns false if the path
+// cannot be trusted.
+bool PreProcessName(base::string16* 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)
diff --git a/sandbox/win/src/handle_closer_agent.cc b/sandbox/win/src/handle_closer_agent.cc
index 9a79d55..ae5c4d1 100644
--- a/sandbox/win/src/handle_closer_agent.cc
+++ b/sandbox/win/src/handle_closer_agent.cc
@@ -89,14 +89,20 @@
 }
 
 // Reads g_handles_to_close and creates the lookup map.
-void HandleCloserAgent::InitializeHandlesToClose() {
+void HandleCloserAgent::InitializeHandlesToClose(bool* is_csrss_connected) {
   CHECK(g_handles_to_close != NULL);
 
+  // Default to connected state
+  *is_csrss_connected = true;
+
   // 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;
+    if (!wcscmp(input, L"ALPC Port")) {
+      *is_csrss_connected = false;
+    }
     HandleMap::mapped_type& handle_names = handles_to_close_[input];
     input = reinterpret_cast<base::char16*>(reinterpret_cast<char*>(entry)
         + entry->offset_to_names);
diff --git a/sandbox/win/src/handle_closer_agent.h b/sandbox/win/src/handle_closer_agent.h
index a3e1502..ca0a6cf 100644
--- a/sandbox/win/src/handle_closer_agent.h
+++ b/sandbox/win/src/handle_closer_agent.h
@@ -10,6 +10,8 @@
 #include "base/win/scoped_handle.h"
 #include "sandbox/win/src/handle_closer.h"
 #include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/target_services.h"
+
 
 namespace sandbox {
 
@@ -20,7 +22,8 @@
   ~HandleCloserAgent();
 
   // Reads the serialized list from the broker and creates the lookup map.
-  void InitializeHandlesToClose();
+  // Updates is_csrss_connected based on type of handles closed.
+  void InitializeHandlesToClose(bool* is_csrss_connected);
 
   // Closes any handles matching those in the lookup map.
   bool CloseHandles();
diff --git a/sandbox/win/src/handle_closer_test.cc b/sandbox/win/src/handle_closer_test.cc
index f1f80e8..1cb2bb5 100644
--- a/sandbox/win/src/handle_closer_test.cc
+++ b/sandbox/win/src/handle_closer_test.cc
@@ -78,7 +78,7 @@
   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')
+  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;
diff --git a/sandbox/win/src/handle_dispatcher.cc b/sandbox/win/src/handle_dispatcher.cc
index 66308f4..fb640ba 100644
--- a/sandbox/win/src/handle_dispatcher.cc
+++ b/sandbox/win/src/handle_dispatcher.cc
@@ -20,10 +20,10 @@
 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_DUPLICATEHANDLEPROXY_TAG,
+       {VOIDPTR_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE}},
+      reinterpret_cast<CallbackGeneric>(
+          &HandleDispatcher::DuplicateHandleProxy)};
 
   ipc_calls_.push_back(duplicate_handle_proxy);
 }
diff --git a/sandbox/win/src/handle_inheritance_test.cc b/sandbox/win/src/handle_inheritance_test.cc
index 37974e3..d8c2808 100644
--- a/sandbox/win/src/handle_inheritance_test.cc
+++ b/sandbox/win/src/handle_inheritance_test.cc
@@ -49,4 +49,4 @@
   }
 }
 
-}
+}  // namespace sandbox
diff --git a/sandbox/win/src/handle_table.cc b/sandbox/win/src/handle_table.cc
deleted file mode 100644
index 5ebcf99..0000000
--- a/sandbox/win/src/handle_table.cc
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. 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
deleted file mode 100644
index 47f625d..0000000
--- a/sandbox/win/src/handle_table.h
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. 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/interception.cc b/sandbox/win/src/interception.cc
index 60dd440..1d858be 100644
--- a/sandbox/win/src/interception.cc
+++ b/sandbox/win/src/interception.cc
@@ -17,27 +17,31 @@
 #include "sandbox/win/src/interception_internal.h"
 #include "sandbox/win/src/interceptors.h"
 #include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_rand.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 {
+namespace sandbox {
 
-const char kMapViewOfSectionName[] = "NtMapViewOfSection";
-const char kUnmapViewOfSectionName[] = "NtUnmapViewOfSection";
+namespace {
 
 // Standard allocation granularity and page size for Windows.
 const size_t kAllocGranularity = 65536;
 const size_t kPageSize = 4096;
 
+}  // namespace
+
+namespace internal {
+
 // 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);
+    GetRandom(&offset);
     offset &= (kAllocGranularity - 1);
   } while (offset > (kAllocGranularity - size));
 
@@ -49,9 +53,7 @@
   return offset & ~(align_size - 1);
 }
 
-}  // namespace
-
-namespace sandbox {
+}  // namespace internal
 
 SANDBOX_INTERCEPT SharedMemory* g_interceptions;
 
@@ -397,7 +399,7 @@
   // 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);
+  size_t thunk_offset = internal::GetGranularAlignedRandomOffset(thunk_bytes);
 
   // Split the base and offset along page boundaries.
   thunk_base += thunk_offset & ~(kPageSize - 1);
@@ -484,7 +486,9 @@
 #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)
+    if (os_info->version() >= base::win::VERSION_WIN10)
+      thunk = new Wow64W10ResolverThunk(child_->Process(), relaxed_);
+    else if (os_info->version() >= base::win::VERSION_WIN8)
       thunk = new Wow64W8ResolverThunk(child_->Process(), relaxed_);
     else
       thunk = new Wow64ResolverThunk(child_->Process(), relaxed_);
diff --git a/sandbox/win/src/interception_unittest.cc b/sandbox/win/src/interception_unittest.cc
index 0fc9b7c..7ce5724 100644
--- a/sandbox/win/src/interception_unittest.cc
+++ b/sandbox/win/src/interception_unittest.cc
@@ -6,8 +6,12 @@
 // The tests require private information so the whole interception.cc file is
 // included from this file.
 
+#include <algorithm>
+#include <set>
+
 #include <windows.h>
 
+#include "base/bits.h"
 #include "base/memory/scoped_ptr.h"
 #include "sandbox/win/src/interception.h"
 #include "sandbox/win/src/interceptors.h"
@@ -17,6 +21,10 @@
 
 namespace sandbox {
 
+namespace internal {
+size_t GetGranularAlignedRandomOffset(size_t size);
+}
+
 // Walks the settings buffer, verifying that the values make sense and counting
 // objects.
 // Arguments:
@@ -75,6 +83,45 @@
   }
 }
 
+TEST(InterceptionManagerTest, GetGranularAlignedRandomOffset) {
+  std::set<size_t> sizes;
+
+  // 544 is current value of interceptions_.size() * sizeof(ThunkData) +
+  // sizeof(DllInterceptionData).
+  const size_t kThunkBytes = 544;
+
+  // ciel(log2(544)) = 10.
+  // Alignment must be 2^10 = 1024.
+  const size_t kAlignmentBits = base::bits::Log2Ceiling(kThunkBytes);
+  const size_t kAlignment = 1 << kAlignmentBits;
+
+  const size_t kAllocGranularity = 65536;
+
+  // Generate enough sample data to ensure there is at least one value in each
+  // potential bucket.
+  for (size_t i = 0; i < 1000000; i++)
+    sizes.insert(internal::GetGranularAlignedRandomOffset(kThunkBytes));
+
+  size_t prev_val = 0;
+  size_t min_val = kAllocGranularity;
+  size_t min_nonzero_val = kAllocGranularity;
+  size_t max_val = 0;
+
+  for (size_t val : sizes) {
+    ASSERT_LT(val, kAllocGranularity);
+    if (prev_val)
+      ASSERT_EQ(val - prev_val, kAlignment);
+    if (val)
+      min_nonzero_val = std::min(val, min_nonzero_val);
+    min_val = std::min(val, min_val);
+    prev_val = val;
+    max_val = std::max(val, max_val);
+  }
+  ASSERT_EQ(max_val, kAllocGranularity - kAlignment);
+  ASSERT_EQ(min_val, 0);
+  ASSERT_EQ(min_nonzero_val, kAlignment);
+}
+
 TEST(InterceptionManagerTest, BufferLayout1) {
   wchar_t exe_name[MAX_PATH];
   ASSERT_NE(0u, GetModuleFileName(NULL, exe_name, MAX_PATH - 1));
diff --git a/sandbox/win/src/ipc_unittest.cc b/sandbox/win/src/ipc_unittest.cc
index b1e74ab..0dc9571 100644
--- a/sandbox/win/src/ipc_unittest.cc
+++ b/sandbox/win/src/ipc_unittest.cc
@@ -392,8 +392,6 @@
   CrossCallParamsMock(uint32 tag, uint32 params_count)
       :  CrossCallParams(tag, params_count) {
   }
- private:
-  void* params[4];
 };
 
 void FakeOkAnswerInChannel(void* channel) {
@@ -584,16 +582,12 @@
 };
 
 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)
-  };
+  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);
 }
@@ -620,10 +614,10 @@
   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::SharedMemIPCServer::ServerControl srv_control = {};
+  srv_control.channel_size = kIPCChannelSize;
+  srv_control.shared_base = reinterpret_cast<char*>(client_control);
+  srv_control.dispatcher = &dispatcher;
 
   sandbox::CrossCallReturn call_return = {0};
   EXPECT_TRUE(SharedMemIPCServer::InvokeCallback(&srv_control, buff,
diff --git a/sandbox/win/src/job.cc b/sandbox/win/src/job.cc
index 8852ab0..9c854e5 100644
--- a/sandbox/win/src/job.cc
+++ b/sandbox/win/src/job.cc
@@ -9,25 +9,26 @@
 
 namespace sandbox {
 
+Job::Job() : job_handle_(NULL) {
+};
+
 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_)
+  if (job_handle_.IsValid())
     return ERROR_ALREADY_INITIALIZED;
 
-  job_handle_ = ::CreateJobObject(NULL,   // No security attribute
-                                  job_name);
-  if (!job_handle_)
+  job_handle_.Set(::CreateJobObject(NULL,   // No security attribute
+                                    job_name));
+  if (!job_handle_.IsValid())
     return ::GetLastError();
 
-  JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0};
-  JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {};
+  JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {};
 
   // Set the settings for the different security levels. Note: The higher levels
   // inherit from the lower levels.
@@ -68,7 +69,7 @@
     }
   }
 
-  if (FALSE == ::SetInformationJobObject(job_handle_,
+  if (FALSE == ::SetInformationJobObject(job_handle_.Get(),
                                          JobObjectExtendedLimitInformation,
                                          &jeli,
                                          sizeof(jeli))) {
@@ -76,7 +77,7 @@
   }
 
   jbur.UIRestrictionsClass = jbur.UIRestrictionsClass & (~ui_exceptions);
-  if (FALSE == ::SetInformationJobObject(job_handle_,
+  if (FALSE == ::SetInformationJobObject(job_handle_.Get(),
                                          JobObjectBasicUIRestrictions,
                                          &jbur,
                                          sizeof(jbur))) {
@@ -87,11 +88,11 @@
 }
 
 DWORD Job::UserHandleGrantAccess(HANDLE handle) {
-  if (!job_handle_)
+  if (!job_handle_.IsValid())
     return ERROR_NO_DATA;
 
   if (!::UserHandleGrantAccess(handle,
-                               job_handle_,
+                               job_handle_.Get(),
                                TRUE)) {  // Access allowed.
     return ::GetLastError();
   }
@@ -99,17 +100,15 @@
   return ERROR_SUCCESS;
 }
 
-HANDLE Job::Detach() {
-  HANDLE handle_temp = job_handle_;
-  job_handle_ = NULL;
-  return handle_temp;
+base::win::ScopedHandle Job::Take() {
+  return job_handle_.Pass();
 }
 
 DWORD Job::AssignProcessToJob(HANDLE process_handle) {
-  if (!job_handle_)
+  if (!job_handle_.IsValid())
     return ERROR_NO_DATA;
 
-  if (FALSE == ::AssignProcessToJobObject(job_handle_, process_handle))
+  if (FALSE == ::AssignProcessToJobObject(job_handle_.Get(), process_handle))
     return ::GetLastError();
 
   return ERROR_SUCCESS;
diff --git a/sandbox/win/src/job.h b/sandbox/win/src/job.h
index 60dc314..4b7cb72 100644
--- a/sandbox/win/src/job.h
+++ b/sandbox/win/src/job.h
@@ -6,6 +6,7 @@
 #define SANDBOX_SRC_JOB_H_
 
 #include "base/basictypes.h"
+#include "base/win/scoped_handle.h"
 #include "sandbox/win/src/restricted_token_utils.h"
 
 namespace sandbox {
@@ -17,7 +18,7 @@
 //   job.AssignProcessToJob(process_handle);
 class Job {
  public:
-  Job() : job_handle_(NULL) { }
+  Job();
 
   ~Job();
 
@@ -47,14 +48,13 @@
   // 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();
+  // Revokes ownership to the job handle and returns it.
+  // If the object is not yet initialized, it returns an invalid handle.
+  base::win::ScopedHandle Take();
 
  private:
   // Handle to the job referenced by the object.
-  HANDLE job_handle_;
+  base::win::ScopedHandle job_handle_;
 
   DISALLOW_COPY_AND_ASSIGN(Job);
 };
diff --git a/sandbox/win/src/job_unittest.cc b/sandbox/win/src/job_unittest.cc
index a1b7aca..d176367 100644
--- a/sandbox/win/src/job_unittest.cc
+++ b/sandbox/win/src/job_unittest.cc
@@ -33,17 +33,17 @@
   ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
 }
 
-// Tests the method "Detach".
-TEST(JobTest, TestDetach) {
-  HANDLE job_handle;
+// Tests the method "Take".
+TEST(JobTest, Take) {
+  base::win::ScopedHandle 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);
+    job_handle = job.Take();
+    ASSERT_TRUE(job_handle.IsValid());
   }
 
   // Check to be sure that the job is still alive even after the object is gone
@@ -56,18 +56,17 @@
   if (job_handle_dup)
     ::CloseHandle(job_handle_dup);
 
-  if (job_handle)
-    ::CloseHandle(job_handle);
+  job_handle.Close();
 
   // Check if the jbo is really dead.
-  job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name");
-  ASSERT_TRUE(job_handle == NULL);
+  job_handle_dup = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name");
+  ASSERT_TRUE(job_handle_dup == NULL);
   ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
 }
 
 // Tests the ui exceptions
 TEST(JobTest, TestExceptions) {
-  HANDLE job_handle;
+  base::win::ScopedHandle job_handle;
   // Scope the creation of Job.
   {
     // Create the job.
@@ -75,18 +74,18 @@
     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);
+    job_handle = job.Take();
+    ASSERT_TRUE(job_handle.IsValid());
 
     JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
     DWORD size = sizeof(jbur);
-    BOOL result = ::QueryInformationJobObject(job_handle,
+    BOOL result = ::QueryInformationJobObject(job_handle.Get(),
                                               JobObjectBasicUIRestrictions,
                                               &jbur, size, &size);
     ASSERT_TRUE(result);
 
     ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD, 0);
-    ::CloseHandle(job_handle);
+    job_handle.Close();
   }
 
   // Scope the creation of Job.
@@ -95,19 +94,18 @@
     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);
+    job_handle = job.Take();
+    ASSERT_TRUE(job_handle.IsValid());
 
     JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
     DWORD size = sizeof(jbur);
-    BOOL result = ::QueryInformationJobObject(job_handle,
+    BOOL result = ::QueryInformationJobObject(job_handle.Get(),
                                               JobObjectBasicUIRestrictions,
                                               &jbur, size, &size);
     ASSERT_TRUE(result);
 
     ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD,
               JOB_OBJECT_UILIMIT_READCLIPBOARD);
-    ::CloseHandle(job_handle);
   }
 }
 
@@ -125,7 +123,7 @@
   Job job;
   ASSERT_EQ(ERROR_NO_DATA, job.UserHandleGrantAccess(NULL));
   ASSERT_EQ(ERROR_NO_DATA, job.AssignProcessToJob(NULL));
-  ASSERT_TRUE(job.Detach() == NULL);
+  ASSERT_FALSE(job.Take().IsValid());
 }
 
 // Tests the initialization of the job with different security level.
@@ -173,12 +171,12 @@
   ASSERT_EQ(ERROR_SUCCESS, job.AssignProcessToJob(pi.process_handle()));
 
   // Get the job handle.
-  HANDLE job_handle = job.Detach();
+  base::win::ScopedHandle job_handle = job.Take();
 
   // Check if the process is in the job.
   JOBOBJECT_BASIC_PROCESS_ID_LIST jbpidl = {0};
   DWORD size = sizeof(jbpidl);
-  result = ::QueryInformationJobObject(job_handle,
+  result = ::QueryInformationJobObject(job_handle.Get(),
                                        JobObjectBasicProcessIdList,
                                        &jbpidl, size, &size);
   EXPECT_TRUE(result);
@@ -188,8 +186,6 @@
   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
index 5527319..53bb7c4 100644
--- a/sandbox/win/src/named_pipe_dispatcher.cc
+++ b/sandbox/win/src/named_pipe_dispatcher.cc
@@ -23,10 +23,15 @@
 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_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);
 }
@@ -51,16 +56,15 @@
   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);
+  base::StringPiece16 dotdot(L"..");
 
-  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"..")
+  for (const base::StringPiece16& path : base::SplitStringPiece(
+           *name, base::string16(1, '/'),
+           base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+    for (const base::StringPiece16& inner : base::SplitStringPiece(
+             path, base::string16(1, '\\'),
+             base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+      if (inner == dotdot)
         return true;
     }
   }
diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h
index 45511a1..010f7cb 100644
--- a/sandbox/win/src/nt_internals.h
+++ b/sandbox/win/src/nt_internals.h
@@ -58,6 +58,7 @@
 typedef CONST STRING* PCOEM_STRING;
 
 #define OBJ_CASE_INSENSITIVE 0x00000040L
+#define OBJ_OPENIF           0x00000080L
 
 typedef struct _OBJECT_ATTRIBUTES {
   ULONG Length;
@@ -307,15 +308,27 @@
 } PROCESSINFOCLASS;
 
 typedef PVOID PPEB;
-typedef PVOID KPRIORITY;
+typedef LONG KPRIORITY;
 
 typedef struct _PROCESS_BASIC_INFORMATION {
-  NTSTATUS ExitStatus;
+  union {
+    NTSTATUS ExitStatus;
+    PVOID padding_for_x64_0;
+  };
   PPEB PebBaseAddress;
   KAFFINITY AffinityMask;
-  KPRIORITY BasePriority;
-  ULONG UniqueProcessId;
-  ULONG InheritedFromUniqueProcessId;
+  union {
+    KPRIORITY BasePriority;
+    PVOID padding_for_x64_1;
+  };
+  union {
+    DWORD UniqueProcessId;
+    PVOID padding_for_x64_2;
+  };
+  union {
+    DWORD InheritedFromUniqueProcessId;
+    PVOID padding_for_x64_3;
+  };
 } PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
 
 typedef NTSTATUS (WINAPI *NtQueryInformationProcessFunction)(
@@ -635,6 +648,11 @@
   SynchronizationEvent
 } EVENT_TYPE, *PEVENT_TYPE;
 
+typedef NTSTATUS (WINAPI* NtCreateDirectoryObjectFunction) (
+    PHANDLE DirectoryHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
+
 typedef NTSTATUS (WINAPI* NtOpenDirectoryObjectFunction) (
     PHANDLE DirectoryHandle,
     ACCESS_MASK DesiredAccess,
diff --git a/sandbox/win/src/policy_broker.cc b/sandbox/win/src/policy_broker.cc
index dc5e18c..c2d25bd 100644
--- a/sandbox/win/src/policy_broker.cc
+++ b/sandbox/win/src/policy_broker.cc
@@ -38,7 +38,7 @@
   if (NULL == g_nt.member) \
     return false
 
-bool SetupNtdllImports(TargetProcess *child) {
+bool InitGlobalNt() {
   HMODULE ntdll = ::GetModuleHandle(kNtdllName);
   base::win::PEImage ntdll_image(ntdll);
 
@@ -75,6 +75,14 @@
   INIT_GLOBAL_RTL(wcslen);
   INIT_GLOBAL_RTL(memcpy);
 
+  return true;
+}
+
+bool SetupNtdllImports(TargetProcess *child) {
+  if (!InitGlobalNt()) {
+    return false;
+  }
+
 #ifndef NDEBUG
   // Verify that the structure is fully initialized.
   for (size_t i = 0; i < sizeof(g_nt)/sizeof(void*); i++)
diff --git a/sandbox/win/src/policy_broker.h b/sandbox/win/src/policy_broker.h
index 1c5cc26..15d3b21 100644
--- a/sandbox/win/src/policy_broker.h
+++ b/sandbox/win/src/policy_broker.h
@@ -11,6 +11,9 @@
 
 class TargetProcess;
 
+// Initializes global imported symbols from ntdll.
+bool InitGlobalNt();
+
 // Sets up interceptions not controlled by explicit policies.
 bool SetupBasicInterceptions(InterceptionManager* manager);
 
diff --git a/sandbox/win/src/policy_engine_opcodes.cc b/sandbox/win/src/policy_engine_opcodes.cc
index 24ba119..dfe42c0 100644
--- a/sandbox/win/src/policy_engine_opcodes.cc
+++ b/sandbox/win/src/policy_engine_opcodes.cc
@@ -9,15 +9,15 @@
 #include "sandbox/win/src/sandbox_types.h"
 
 namespace {
-const unsigned short kMaxUniStrSize = 0xfffc;
+const unsigned short kMaxUniStrSize = 0xfffc / sizeof(wchar_t);
 
 bool InitStringUnicode(const wchar_t* source, size_t length,
                        UNICODE_STRING* ustring) {
+  if (length > kMaxUniStrSize) {
+    return false;
+  }
   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;
@@ -56,9 +56,6 @@
 EvalResult OpcodeEval<OP_ALWAYS_FALSE>(PolicyOpcode* opcode,
                                        const ParameterSet* param,
                                        MatchContext* context) {
-  UNREFERENCED_PARAMETER(opcode);
-  UNREFERENCED_PARAMETER(param);
-  UNREFERENCED_PARAMETER(context);
   return EVAL_FALSE;
 }
 
@@ -74,9 +71,6 @@
 EvalResult OpcodeEval<OP_ALWAYS_TRUE>(PolicyOpcode* opcode,
                                       const ParameterSet* param,
                                       MatchContext* context) {
-  UNREFERENCED_PARAMETER(opcode);
-  UNREFERENCED_PARAMETER(param);
-  UNREFERENCED_PARAMETER(context);
   return EVAL_TRUE;
 }
 
@@ -97,8 +91,6 @@
 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);
@@ -134,7 +126,6 @@
 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;
@@ -176,7 +167,6 @@
 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;
 
@@ -206,7 +196,6 @@
 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;
 
@@ -314,9 +303,10 @@
     }
 
     UNICODE_STRING match_ustr;
-    InitStringUnicode(match_str, match_len, &match_ustr);
     UNICODE_STRING source_ustr;
-    InitStringUnicode(source_str, match_len, &source_ustr);
+    if (!InitStringUnicode(match_str, match_len, &match_ustr) ||
+        !InitStringUnicode(source_str, match_len, &source_ustr))
+      return EVAL_ERROR;
 
     if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr,
                                           case_sensitive)) {
@@ -328,9 +318,10 @@
     }
   } 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);
+    if (!InitStringUnicode(match_str, match_len, &match_ustr) ||
+        !InitStringUnicode(source_str, match_len, &source_ustr))
+      return EVAL_ERROR;
 
     do {
       if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr,
diff --git a/sandbox/win/src/policy_target_test.cc b/sandbox/win/src/policy_target_test.cc
index 4395a4f..bb1f0b2 100644
--- a/sandbox/win/src/policy_target_test.cc
+++ b/sandbox/win/src/policy_target_test.cc
@@ -376,8 +376,8 @@
   GetModuleFileNameW(NULL, prog_name, MAX_PATH);
 
   TargetPolicy* policy = broker->CreatePolicy();
-  void* shared_handle = policy->AddHandleToShare(
-      read_only_view.handle());
+  void* shared_handle =
+      policy->AddHandleToShare(read_only_view.handle().GetHandle());
 
   base::string16 arguments(L"\"");
   arguments += prog_name;
diff --git a/sandbox/win/src/process_mitigations.cc b/sandbox/win/src/process_mitigations.cc
index d187c55..8072440 100644
--- a/sandbox/win/src/process_mitigations.cc
+++ b/sandbox/win/src/process_mitigations.cc
@@ -9,6 +9,7 @@
 #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/sandbox_rand.h"
 #include "sandbox/win/src/win_utils.h"
 
 namespace {
@@ -87,7 +88,6 @@
     } 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;
@@ -122,7 +122,7 @@
 
   // Enable ASLR policies.
   if (flags & MITIGATION_RELOCATE_IMAGE) {
-    PROCESS_MITIGATION_ASLR_POLICY policy = { 0 };
+    PROCESS_MITIGATION_ASLR_POLICY policy = {};
     policy.EnableForceRelocateImages = true;
     policy.DisallowStrippedImages = (flags &
         MITIGATION_RELOCATE_IMAGE_REQUIRED) ==
@@ -137,7 +137,7 @@
 
   // Enable strict handle policies.
   if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
-    PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = { 0 };
+    PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = {};
     policy.HandleExceptionsPermanentlyEnabled =
         policy.RaiseExceptionOnInvalidHandleReference = true;
 
@@ -150,7 +150,7 @@
 
   // Enable system call policies.
   if (flags & MITIGATION_WIN32K_DISABLE) {
-    PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = { 0 };
+    PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
     policy.DisallowWin32kSystemCalls = true;
 
     if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy,
@@ -162,7 +162,7 @@
 
   // Enable system call policies.
   if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
-    PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = { 0 };
+    PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {};
     policy.DisableExtensionPoints = true;
 
     if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy,
@@ -286,7 +286,7 @@
 #if !defined(_WIN64)
   if (flags & MITIGATION_BOTTOM_UP_ASLR) {
     unsigned int limit;
-    rand_s(&limit);
+    GetRandom(&limit);
     char* ptr = 0;
     const size_t kMask64k = 0xFFFF;
     // Random range (512k-16.5mb) in 64k steps.
diff --git a/sandbox/win/src/process_mitigations_test.cc b/sandbox/win/src/process_mitigations_test.cc
index 4d2e9c6..080d8ec 100644
--- a/sandbox/win/src/process_mitigations_test.cc
+++ b/sandbox/win/src/process_mitigations_test.cc
@@ -30,26 +30,30 @@
 
 GetProcessMitigationPolicyFunction get_process_mitigation_policy;
 
+#if !defined(_WIN64)
 bool CheckWin8DepPolicy() {
-  PROCESS_MITIGATION_DEP_POLICY policy;
+  PROCESS_MITIGATION_DEP_POLICY policy = {};
   if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessDEPPolicy,
                                      &policy, sizeof(policy))) {
     return false;
   }
   return policy.Enable && policy.Permanent;
 }
+#endif  // !defined(_WIN64)
 
+#if defined(NDEBUG)
 bool CheckWin8AslrPolicy() {
-  PROCESS_MITIGATION_ASLR_POLICY policy;
+  PROCESS_MITIGATION_ASLR_POLICY policy = {};
   if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessASLRPolicy,
                                      &policy, sizeof(policy))) {
      return false;
   }
   return policy.EnableForceRelocateImages && policy.DisallowStrippedImages;
 }
+#endif  // defined(NDEBUG)
 
 bool CheckWin8StrictHandlePolicy() {
-  PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy;
+  PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = {};
   if (!get_process_mitigation_policy(::GetCurrentProcess(),
                                      ProcessStrictHandleCheckPolicy,
                                      &policy, sizeof(policy))) {
@@ -60,7 +64,7 @@
 }
 
 bool CheckWin8Win32CallPolicy() {
-  PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy;
+  PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
   if (!get_process_mitigation_policy(::GetCurrentProcess(),
                                      ProcessSystemCallDisablePolicy,
                                      &policy, sizeof(policy))) {
@@ -70,7 +74,7 @@
 }
 
 bool CheckWin8DllExtensionPolicy() {
-  PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy;
+  PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {};
   if (!get_process_mitigation_policy(::GetCurrentProcess(),
                                      ProcessExtensionPointDisablePolicy,
                                      &policy, sizeof(policy))) {
@@ -91,8 +95,10 @@
   if (!get_process_mitigation_policy)
     return SBOX_TEST_NOT_FOUND;
 
+#if !defined(_WIN64)  // DEP is always enabled on 64-bit.
   if (!CheckWin8DepPolicy())
     return SBOX_TEST_FIRST_ERROR;
+#endif
 
 #if defined(NDEBUG)  // ASLR cannot be forced in debug builds.
   if (!CheckWin8AslrPolicy())
@@ -165,9 +171,7 @@
       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;
 
diff --git a/sandbox/win/src/process_thread_dispatcher.cc b/sandbox/win/src/process_thread_dispatcher.cc
index ca17d49..90cad63 100644
--- a/sandbox/win/src/process_thread_dispatcher.cc
+++ b/sandbox/win/src/process_thread_dispatcher.cc
@@ -97,34 +97,30 @@
 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)
-  };
+      {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)
-  };
+      {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)
-  };
+      {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)
-  };
+      {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_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);
diff --git a/sandbox/win/src/process_thread_interception.cc b/sandbox/win/src/process_thread_interception.cc
index 45926bc..2d459b6 100644
--- a/sandbox/win/src/process_thread_interception.cc
+++ b/sandbox/win/src/process_thread_interception.cc
@@ -267,7 +267,8 @@
                                  LPVOID environment, LPCWSTR current_directory,
                                  LPSTARTUPINFOW startup_info,
                                  LPPROCESS_INFORMATION process_information) {
-  if (orig_CreateProcessW(application_name, command_line, process_attributes,
+  if (SandboxFactory::GetTargetServices()->GetState()->IsCsrssConnected() &&
+      orig_CreateProcessW(application_name, command_line, process_attributes,
                           thread_attributes, inherit_handles, flags,
                           environment, current_directory, startup_info,
                           process_information)) {
@@ -278,6 +279,8 @@
   if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
     return FALSE;
 
+  // Don't call GetLastError before InitCalled() succeeds because kernel32 may
+  // not be mapped yet.
   DWORD original_error = ::GetLastError();
 
   do {
@@ -337,6 +340,8 @@
   if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
     return FALSE;
 
+  // Don't call GetLastError before InitCalled() succeeds because kernel32 may
+  // not be mapped yet.
   DWORD original_error = ::GetLastError();
 
   do {
diff --git a/sandbox/win/src/process_thread_policy.cc b/sandbox/win/src/process_thread_policy.cc
index 0653591..b58a287 100644
--- a/sandbox/win/src/process_thread_policy.cc
+++ b/sandbox/win/src/process_thread_policy.cc
@@ -117,7 +117,7 @@
   client_id.UniqueThread =
       reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id));
 
-  HANDLE local_handle;
+  HANDLE local_handle = NULL;
   NTSTATUS status = NtOpenThread(&local_handle, desired_access, &attributes,
                                  &client_id);
   if (NT_SUCCESS(status)) {
@@ -148,7 +148,7 @@
   CLIENT_ID client_id = {0};
   client_id.UniqueProcess = reinterpret_cast<PVOID>(
                                 static_cast<ULONG_PTR>(client_info.process_id));
-  HANDLE local_handle;
+  HANDLE local_handle = NULL;
   NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes,
                                   &client_id);
   if (NT_SUCCESS(status)) {
@@ -173,7 +173,7 @@
   if (CURRENT_PROCESS != process)
     return STATUS_ACCESS_DENIED;
 
-  HANDLE local_handle;
+  HANDLE local_handle = NULL;
   NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access,
                                        &local_handle);
   if (NT_SUCCESS(status)) {
@@ -198,7 +198,7 @@
   if (CURRENT_PROCESS != process)
     return STATUS_ACCESS_DENIED;
 
-  HANDLE local_handle;
+  HANDLE local_handle = NULL;
   NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access,
                                          attributes, &local_handle);
   if (NT_SUCCESS(status)) {
diff --git a/sandbox/win/src/registry_dispatcher.cc b/sandbox/win/src/registry_dispatcher.cc
index 967fe65..267a592 100644
--- a/sandbox/win/src/registry_dispatcher.cc
+++ b/sandbox/win/src/registry_dispatcher.cc
@@ -42,15 +42,18 @@
 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)
-  };
+      {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_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);
diff --git a/sandbox/win/src/registry_policy.cc b/sandbox/win/src/registry_policy.cc
index b0f24a7..58e4e20 100644
--- a/sandbox/win/src/registry_policy.cc
+++ b/sandbox/win/src/registry_policy.cc
@@ -43,7 +43,7 @@
   OBJECT_BASIC_INFORMATION info = {0};
   status = NtQueryObject(handle, ObjectBasicInformation, &info, sizeof(info),
                          NULL);
-  NtClose(handle);
+  CHECK(NT_SUCCESS(NtClose(handle)));
   if (!NT_SUCCESS(status))
     return status;
 
diff --git a/sandbox/win/src/restricted_token.cc b/sandbox/win/src/restricted_token.cc
index 7ebef3d..f0fc4cb 100644
--- a/sandbox/win/src/restricted_token.cc
+++ b/sandbox/win/src/restricted_token.cc
@@ -7,53 +7,75 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
 #include "sandbox/win/src/acl.h"
 #include "sandbox/win/src/win_utils.h"
 
+namespace {
+
+// Calls GetTokenInformation with the desired |info_class| and returns a buffer
+// with the result.
+scoped_ptr<BYTE[]> GetTokenInfo(const base::win::ScopedHandle& token,
+                                TOKEN_INFORMATION_CLASS info_class,
+                                DWORD* error) {
+  // Get the required buffer size.
+  DWORD size = 0;
+  ::GetTokenInformation(token.Get(), info_class, NULL, 0,  &size);
+  if (!size) {
+    *error = ::GetLastError();
+    return nullptr;
+  }
+
+  scoped_ptr<BYTE[]> buffer(new BYTE[size]);
+  if (!::GetTokenInformation(token.Get(), info_class, buffer.get(), size,
+                             &size)) {
+    *error = ::GetLastError();
+    return nullptr;
+  }
+
+  *error = ERROR_SUCCESS;
+  return buffer.Pass();
+}
+
+}  // namespace
+
 namespace sandbox {
 
 RestrictedToken::RestrictedToken()
-    : init_(false),
-      effective_token_(NULL),
-      integrity_level_(INTEGRITY_LEVEL_LAST) {
+    : integrity_level_(INTEGRITY_LEVEL_LAST),
+      init_(false) {
 }
 
 RestrictedToken::~RestrictedToken() {
-  if (effective_token_)
-    CloseHandle(effective_token_);
 }
 
-unsigned RestrictedToken::Init(const HANDLE effective_token) {
+DWORD RestrictedToken::Init(const HANDLE effective_token) {
   if (init_)
     return ERROR_ALREADY_INITIALIZED;
 
+  HANDLE temp_token;
   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 {
+    if (!::DuplicateHandle(::GetCurrentProcess(), effective_token,
+                           ::GetCurrentProcess(), &temp_token,
+                           0, FALSE, DUPLICATE_SAME_ACCESS)) {
       return ::GetLastError();
     }
   } else {
-    if (!::OpenProcessToken(::GetCurrentProcess(),
-                            TOKEN_ALL_ACCESS,
-                            &effective_token_))
+    if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+                            &temp_token)) {
       return ::GetLastError();
+    }
   }
+  effective_token_.Set(temp_token);
 
   init_ = true;
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE *token_handle) const {
+DWORD RestrictedToken::GetRestrictedToken(
+    base::win::ScopedHandle* token) const {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
@@ -95,13 +117,13 @@
   }
 
   BOOL result = TRUE;
-  HANDLE new_token = NULL;
+  HANDLE new_token_handle = 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_,
+    result = ::CreateRestrictedToken(effective_token_.Get(),
                                      SANDBOX_INERT,
                                      static_cast<DWORD>(deny_size),
                                      deny_only_array,
@@ -109,15 +131,16 @@
                                      privileges_to_disable_array,
                                      static_cast<DWORD>(restrict_size),
                                      sids_to_restrict_array,
-                                     &new_token);
+                                     &new_token_handle);
   } 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,
+    result = ::DuplicateTokenEx(effective_token_.Get(), TOKEN_ALL_ACCESS, NULL,
                                 SecurityIdentification, TokenPrimary,
-                                &new_token);
+                                &new_token_handle);
   }
+  auto last_error = ::GetLastError();
 
   if (deny_only_array)
     delete[] deny_only_array;
@@ -129,99 +152,77 @@
     delete[] privileges_to_disable_array;
 
   if (!result)
-    return ::GetLastError();
+    return last_error;
+
+  base::win::ScopedHandle new_token(new_token_handle);
 
   // Modify the default dacl on the token to contain Restricted and the user.
-  if (!AddSidToDefaultDacl(new_token, WinRestrictedCodeSid, GENERIC_ALL))
+  if (!AddSidToDefaultDacl(new_token.Get(), WinRestrictedCodeSid, GENERIC_ALL))
     return ::GetLastError();
 
-  if (!AddUserSidToDefaultDacl(new_token, GENERIC_ALL))
+  if (!AddUserSidToDefaultDacl(new_token.Get(), GENERIC_ALL))
     return ::GetLastError();
 
-  DWORD error = SetTokenIntegrityLevel(new_token, integrity_level_);
+  DWORD error = SetTokenIntegrityLevel(new_token.Get(), 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)
+  HANDLE token_handle;
+  if (!::DuplicateHandle(::GetCurrentProcess(), new_token.Get(),
+                         ::GetCurrentProcess(), &token_handle,
+                         TOKEN_ALL_ACCESS, FALSE,  // Don't inherit.
+                         0)) {
     return ::GetLastError();
+  }
 
+  token->Set(token_handle);
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
-    HANDLE *token_handle) const {
+DWORD RestrictedToken::GetRestrictedTokenForImpersonation(
+    base::win::ScopedHandle* token) const {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
 
-  HANDLE restricted_token_handle;
-  unsigned err_code = GetRestrictedTokenHandle(&restricted_token_handle);
+  base::win::ScopedHandle restricted_token;
+  DWORD err_code = GetRestrictedToken(&restricted_token);
   if (ERROR_SUCCESS != err_code)
     return err_code;
 
-  HANDLE impersonation_token;
-  if (!::DuplicateToken(restricted_token_handle,
+  HANDLE impersonation_token_handle;
+  if (!::DuplicateToken(restricted_token.Get(),
                         SecurityImpersonation,
-                        &impersonation_token)) {
-    ::CloseHandle(restricted_token_handle);
+                        &impersonation_token_handle)) {
+    return ::GetLastError();
+  }
+  base::win::ScopedHandle impersonation_token(impersonation_token_handle);
+
+  HANDLE token_handle;
+  if (!::DuplicateHandle(::GetCurrentProcess(), impersonation_token.Get(),
+                         ::GetCurrentProcess(), &token_handle,
+                         TOKEN_ALL_ACCESS, FALSE,  // Don't inherit.
+                         0)) {
     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();
-
+  token->Set(token_handle);
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
+DWORD RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
 
-  TOKEN_GROUPS *token_groups = NULL;
-  DWORD size = 0;
+  DWORD error;
+  scoped_ptr<BYTE[]> buffer =
+      GetTokenInfo(effective_token_, TokenGroups, &error);
 
-  BOOL result = ::GetTokenInformation(effective_token_,
-                                      TokenGroups,
-                                      NULL,  // No buffer.
-                                      0,  // Size is 0.
-                                      &size);
-  if (!size)
-    return ::GetLastError();
+  if (!buffer)
+    return error;
 
-  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();
-  }
+  TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
 
   // Build the list of the deny only group SIDs
   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
@@ -244,12 +245,10 @@
     }
   }
 
-  delete[] reinterpret_cast<BYTE*>(token_groups);
-
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
+DWORD RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
@@ -258,62 +257,42 @@
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::AddUserSidForDenyOnly() {
+DWORD 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]);
+  scoped_ptr<BYTE[]> buffer(new BYTE[size]);
+  TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(buffer.get());
 
-  BOOL result = ::GetTokenInformation(effective_token_,
-                                      TokenUser,
-                                      token_user,
-                                      size,
-                                      &size);
+  BOOL result = ::GetTokenInformation(effective_token_.Get(), TokenUser,
+                                      token_user, size, &size);
 
-  if (!result) {
-    delete[] reinterpret_cast<BYTE*>(token_user);
+  if (!result)
     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(
+DWORD 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;
+  DWORD error;
+  scoped_ptr<BYTE[]> buffer =
+      GetTokenInfo(effective_token_, TokenPrivileges, &error);
 
-  BOOL result = ::GetTokenInformation(effective_token_,
-                                      TokenPrivileges,
-                                      NULL,  // No buffer.
-                                      0,  // Size is 0.
-                                      &size);
-  if (!size)
-    return ::GetLastError();
+  if (!buffer)
+    return error;
 
-  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();
-  }
-
+  TOKEN_PRIVILEGES* token_privileges =
+      reinterpret_cast<TOKEN_PRIVILEGES*>(buffer.get());
 
   // Build the list of privileges to disable
   for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
@@ -334,12 +313,10 @@
     }
   }
 
-  delete[] reinterpret_cast<BYTE *>(token_privileges);
-
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
+DWORD RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
@@ -353,7 +330,7 @@
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::AddRestrictingSid(const Sid &sid) {
+DWORD RestrictedToken::AddRestrictingSid(const Sid &sid) {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
@@ -362,32 +339,19 @@
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::AddRestrictingSidLogonSession() {
+DWORD RestrictedToken::AddRestrictingSidLogonSession() {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
 
-  TOKEN_GROUPS *token_groups = NULL;
-  DWORD size = 0;
+  DWORD error;
+  scoped_ptr<BYTE[]> buffer =
+      GetTokenInfo(effective_token_, TokenGroups, &error);
 
-  BOOL result = ::GetTokenInformation(effective_token_,
-                                      TokenGroups,
-                                      NULL,  // No buffer.
-                                      0,  // Size is 0.
-                                      &size);
-  if (!size)
-    return ::GetLastError();
+  if (!buffer)
+    return error;
 
-  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();
-  }
+  TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
 
   SID *logon_sid = NULL;
   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
@@ -400,67 +364,47 @@
   if (logon_sid)
     sids_to_restrict_.push_back(logon_sid);
 
-  delete[] reinterpret_cast<BYTE*>(token_groups);
-
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
+DWORD 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]);
+  scoped_ptr<BYTE[]> buffer(new BYTE[size]);
+  TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(buffer.get());
 
-  BOOL result = ::GetTokenInformation(effective_token_,
-                                      TokenUser,
-                                      token_user,
-                                      size,
-                                      &size);
+  BOOL result = ::GetTokenInformation(effective_token_.Get(), TokenUser,
+                                      token_user, size, &size);
 
-  if (!result) {
-    delete[] reinterpret_cast<BYTE*>(token_user);
+  if (!result)
     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() {
+DWORD RestrictedToken::AddRestrictingSidAllSids() {
   DCHECK(init_);
   if (!init_)
     return ERROR_NO_TOKEN;
 
   // Add the current user to the list.
-  unsigned error = AddRestrictingSidCurrentUser();
+  DWORD error = AddRestrictingSidCurrentUser();
   if (ERROR_SUCCESS != error)
     return error;
 
-  TOKEN_GROUPS *token_groups = NULL;
-  DWORD size = 0;
+  scoped_ptr<BYTE[]> buffer =
+      GetTokenInfo(effective_token_, TokenGroups, &error);
 
-  // Get the buffer size required.
-  BOOL result = ::GetTokenInformation(effective_token_, TokenGroups, NULL, 0,
-                                      &size);
-  if (!size)
-    return ::GetLastError();
+  if (!buffer)
+    return error;
 
-  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();
-  }
+  TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
 
   // Build the list of restricting sids from all groups.
   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
@@ -468,12 +412,10 @@
       AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
   }
 
-  delete[] reinterpret_cast<BYTE*>(token_groups);
-
   return ERROR_SUCCESS;
 }
 
-unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
+DWORD RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
   integrity_level_ = integrity_level;
   return ERROR_SUCCESS;
 }
diff --git a/sandbox/win/src/restricted_token.h b/sandbox/win/src/restricted_token.h
index 565880e..b9a2d4b 100644
--- a/sandbox/win/src/restricted_token.h
+++ b/sandbox/win/src/restricted_token.h
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/strings/string16.h"
+#include "base/win/scoped_handle.h"
 #include "sandbox/win/src/restricted_token_utils.h"
 #include "sandbox/win/src/security_level.h"
 #include "sandbox/win/src/sid.h"
@@ -28,20 +29,19 @@
 // any token handle.
 // Sample usage:
 //    RestrictedToken restricted_token;
-//    unsigned err_code = restricted_token.Init(NULL);  // Use the current
-//                                                      // effective token
+//    DWORD 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);
+//    base::win::ScopedHandle token_handle;
+//    err_code = restricted_token.GetRestrictedToken(&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.
@@ -51,26 +51,24 @@
   // 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);
+  DWORD 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.
+  // Creates a 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 GetRestrictedTokenHandle(HANDLE *token_handle) const;
+  DWORD GetRestrictedToken(base::win::ScopedHandle* token) 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.
+  // for impersonation. Returns this impersonation 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.
   //
-  // The sample usage is the same as the GetRestrictedTokenHandle function.
-  unsigned GetRestrictedTokenHandleForImpersonation(HANDLE *token_handle) const;
+  // The sample usage is the same as the GetRestrictedToken function.
+  DWORD GetRestrictedTokenForImpersonation(
+      base::win::ScopedHandle* token) 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,
@@ -88,7 +86,7 @@
   //    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);
+  DWORD 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.
@@ -96,13 +94,13 @@
   //
   // Sample Usage:
   //    restricted_token.AddSidForDenyOnly(ATL::Sids::Admins().GetPSID());
-  unsigned AddSidForDenyOnly(const Sid &sid);
+  DWORD 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();
+  DWORD 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
@@ -117,8 +115,7 @@
   //    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);
+  DWORD DeleteAllPrivileges(const std::vector<base::string16> *exceptions);
 
   // Adds a privilege to the list of privileges to remove in the restricted
   // token.
@@ -130,7 +127,7 @@
   //
   // Sample usage:
   //    restricted_token.DeletePrivilege(SE_LOAD_DRIVER_NAME);
-  unsigned DeletePrivilege(const wchar_t *privilege);
+  DWORD 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.
@@ -142,7 +139,7 @@
   // 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);
+  DWORD AddRestrictingSid(const Sid &sid);
 
   // Adds the logon sid of the token in the list of restricting sids for the
   // restricted token.
@@ -150,7 +147,7 @@
   // 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();
+  DWORD AddRestrictingSidLogonSession();
 
   // Adds the owner sid of the token in the list of restricting sids for the
   // restricted token.
@@ -158,18 +155,18 @@
   // 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();
+  DWORD 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();
+  DWORD 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);
+  DWORD SetIntegrityLevel(IntegrityLevel integrity_level);
 
  private:
   // The list of restricting sids in the restricted token.
@@ -179,7 +176,7 @@
   // 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_;
+  base::win::ScopedHandle 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)
diff --git a/sandbox/win/src/restricted_token_unittest.cc b/sandbox/win/src/restricted_token_unittest.cc
index 8186f9c..fca1a07 100644
--- a/sandbox/win/src/restricted_token_unittest.cc
+++ b/sandbox/win/src/restricted_token_unittest.cc
@@ -8,6 +8,8 @@
 #include <atlbase.h>
 #include <atlsecurity.h>
 #include <vector>
+
+#include "base/win/scoped_handle.h"
 #include "sandbox/win/src/restricted_token.h"
 #include "sandbox/win/src/sid.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -38,12 +40,12 @@
 
   // Get the handle to the restricted token.
 
-  HANDLE restricted_token_handle = NULL;
+  base::win::ScopedHandle restricted_token_handle;
   ASSERT_EQ(ERROR_SUCCESS,
-      token_default.GetRestrictedTokenHandle(&restricted_token_handle));
+      token_default.GetRestrictedToken(&restricted_token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(restricted_token_handle);
+  restricted_token.Attach(restricted_token_handle.Take());
 
   ATL::CSid sid_user_restricted;
   ATL::CSid sid_user_default;
@@ -80,12 +82,12 @@
 
   // Get the handle to the restricted token.
 
-  HANDLE restricted_token_handle = NULL;
+  base::win::ScopedHandle restricted_token_handle;
   ASSERT_EQ(ERROR_SUCCESS,
-      token.GetRestrictedTokenHandle(&restricted_token_handle));
+      token.GetRestrictedToken(&restricted_token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(restricted_token_handle);
+  restricted_token.Attach(restricted_token_handle.Take());
 
   ATL::CSid sid_restricted;
   ATL::CSid sid_default;
@@ -104,14 +106,14 @@
   ASSERT_EQ(ERROR_SUCCESS,
             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
 
-  HANDLE restricted_token;
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&restricted_token));
+  base::win::ScopedHandle restricted_token;
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&restricted_token));
 
-  ASSERT_TRUE(::IsTokenRestricted(restricted_token));
+  ASSERT_TRUE(::IsTokenRestricted(restricted_token.Get()));
 
   DWORD length = 0;
   TOKEN_TYPE type;
-  ASSERT_TRUE(::GetTokenInformation(restricted_token,
+  ASSERT_TRUE(::GetTokenInformation(restricted_token.Get(),
                                     ::TokenType,
                                     &type,
                                     sizeof(type),
@@ -119,22 +121,19 @@
 
   ASSERT_EQ(type, TokenPrimary);
 
-  HANDLE impersonation_token;
+  base::win::ScopedHandle impersonation_token;
   ASSERT_EQ(ERROR_SUCCESS,
-      token.GetRestrictedTokenHandleForImpersonation(&impersonation_token));
+      token.GetRestrictedTokenForImpersonation(&impersonation_token));
 
-  ASSERT_TRUE(::IsTokenRestricted(impersonation_token));
+  ASSERT_TRUE(::IsTokenRestricted(impersonation_token.Get()));
 
-  ASSERT_TRUE(::GetTokenInformation(impersonation_token,
+  ASSERT_TRUE(::GetTokenInformation(impersonation_token.Get(),
                                     ::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.
@@ -145,11 +144,11 @@
   ASSERT_EQ(ERROR_SUCCESS,
             token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
 
-  HANDLE handle;
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&handle));
+  base::win::ScopedHandle handle;
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(handle);
+  restricted_token.Attach(handle.Take());
 
   ATL::CDacl dacl;
   ASSERT_TRUE(restricted_token.GetDefaultDacl(&dacl));
@@ -173,14 +172,14 @@
 // Tests the method "AddSidForDenyOnly".
 TEST(RestrictedTokenTest, DenySid) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
   ASSERT_EQ(ERROR_SUCCESS, token.AddSidForDenyOnly(Sid(WinWorldSid)));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   ATL::CTokenGroups groups;
   ASSERT_TRUE(restricted_token.GetGroups(&groups));
@@ -200,14 +199,14 @@
 // Tests the method "AddAllSidsForDenyOnly".
 TEST(RestrictedTokenTest, DenySids) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
   ASSERT_EQ(ERROR_SUCCESS, token.AddAllSidsForDenyOnly(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   ATL::CTokenGroups groups;
   ASSERT_TRUE(restricted_token.GetGroups(&groups));
@@ -229,17 +228,17 @@
 // Tests the method "AddAllSidsForDenyOnly" using an exception list.
 TEST(RestrictedTokenTest, DenySidsException) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   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));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   ATL::CTokenGroups groups;
   ASSERT_TRUE(restricted_token.GetGroups(&groups));
@@ -265,14 +264,14 @@
 // Tests test method AddOwnerSidForDenyOnly.
 TEST(RestrictedTokenTest, DenyOwnerSid) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
   ASSERT_EQ(ERROR_SUCCESS, token.AddUserSidForDenyOnly());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   ATL::CTokenGroups groups;
   ASSERT_TRUE(restricted_token.GetGroups(&groups));
@@ -295,22 +294,23 @@
 // Tests test method AddOwnerSidForDenyOnly with a custom effective token.
 TEST(RestrictedTokenTest, DenyOwnerSidCustom) {
   // Get the current process token.
-  HANDLE token_handle = INVALID_HANDLE_VALUE;
+  HANDLE access_handle = INVALID_HANDLE_VALUE;
   ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
-                                 &token_handle));
+                                 &access_handle));
 
-  ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
+  ASSERT_NE(INVALID_HANDLE_VALUE, access_handle);
 
   ATL::CAccessToken access_token;
-  access_token.Attach(token_handle);
+  access_token.Attach(access_handle);
 
   RestrictedToken token;
+  base::win::ScopedHandle token_handle;
   ASSERT_EQ(ERROR_SUCCESS, token.Init(access_token.GetHandle()));
   ASSERT_EQ(ERROR_SUCCESS, token.AddUserSidForDenyOnly());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   ATL::CTokenGroups groups;
   ASSERT_TRUE(restricted_token.GetGroups(&groups));
@@ -333,14 +333,14 @@
 // Tests the method DeleteAllPrivileges.
 TEST(RestrictedTokenTest, DeleteAllPrivileges) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
   ASSERT_EQ(ERROR_SUCCESS, token.DeleteAllPrivileges(NULL));
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   ATL::CTokenPrivileges privileges;
   ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
@@ -351,17 +351,17 @@
 // Tests the method DeleteAllPrivileges with an exception list.
 TEST(RestrictedTokenTest, DeleteAllPrivilegesException) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   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));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   ATL::CTokenPrivileges privileges;
   ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
@@ -381,14 +381,14 @@
 // Tests the method DeletePrivilege.
 TEST(RestrictedTokenTest, DeletePrivilege) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   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));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   ATL::CTokenPrivileges privileges;
   ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
@@ -441,15 +441,15 @@
 // Tests the method AddRestrictingSid.
 TEST(RestrictedTokenTest, AddRestrictingSid) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   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));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   CheckRestrictingSid(restricted_token, ATL::Sids::World(), 1);
 }
@@ -457,14 +457,14 @@
 // Tests the method AddRestrictingSidCurrentUser.
 TEST(RestrictedTokenTest, AddRestrictingSidCurrentUser) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
   ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidCurrentUser());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
   ATL::CSid user;
   restricted_token.GetUser(&user);
 
@@ -474,22 +474,23 @@
 // Tests the method AddRestrictingSidCurrentUser with a custom effective token.
 TEST(RestrictedTokenTest, AddRestrictingSidCurrentUserCustom) {
   // Get the current process token.
-  HANDLE token_handle = INVALID_HANDLE_VALUE;
+  HANDLE access_handle = INVALID_HANDLE_VALUE;
   ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
-                                 &token_handle));
+                                 &access_handle));
 
-  ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
+  ASSERT_NE(INVALID_HANDLE_VALUE, access_handle);
 
   ATL::CAccessToken access_token;
-  access_token.Attach(token_handle);
+  access_token.Attach(access_handle);
 
   RestrictedToken token;
+  base::win::ScopedHandle token_handle;
   ASSERT_EQ(ERROR_SUCCESS, token.Init(access_token.GetHandle()));
   ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidCurrentUser());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
   ATL::CSid user;
   restricted_token.GetUser(&user);
 
@@ -499,14 +500,14 @@
 // Tests the method AddRestrictingSidLogonSession.
 TEST(RestrictedTokenTest, AddRestrictingSidLogonSession) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
   ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidLogonSession());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
   ATL::CSid session;
   restricted_token.GetLogonSid(&session);
 
@@ -516,17 +517,17 @@
 // Tests adding a lot of restricting sids.
 TEST(RestrictedTokenTest, AddMultipleRestrictingSids) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   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));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
   ATL::CSid session;
   restricted_token.GetLogonSid(&session);
 
@@ -548,14 +549,14 @@
 // Tests the method "AddRestrictingSidAllSids".
 TEST(RestrictedTokenTest, AddAllSidToRestrictingSids) {
   RestrictedToken token;
-  HANDLE token_handle = NULL;
+  base::win::ScopedHandle token_handle;
 
   ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
   ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidAllSids());
-  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedToken(&token_handle));
 
   ATL::CAccessToken restricted_token;
-  restricted_token.Attach(token_handle);
+  restricted_token.Attach(token_handle.Take());
 
   ATL::CTokenGroups groups;
   ASSERT_TRUE(restricted_token.GetGroups(&groups));
diff --git a/sandbox/win/src/restricted_token_utils.cc b/sandbox/win/src/restricted_token_utils.cc
index 5e06daa..4a3d05c 100644
--- a/sandbox/win/src/restricted_token_utils.cc
+++ b/sandbox/win/src/restricted_token_utils.cc
@@ -10,7 +10,6 @@
 
 #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"
@@ -19,13 +18,10 @@
 
 namespace sandbox {
 
-DWORD CreateRestrictedToken(HANDLE *token_handle,
-                            TokenLevel security_level,
+DWORD CreateRestrictedToken(TokenLevel security_level,
                             IntegrityLevel integrity_level,
-                            TokenType token_type) {
-  if (!token_handle)
-    return ERROR_BAD_ARGUMENTS;
-
+                            TokenType token_type,
+                            base::win::ScopedHandle* token) {
   RestrictedToken restricted_token;
   restricted_token.Init(NULL);  // Initialized with the current process token
 
@@ -123,12 +119,11 @@
 
   switch (token_type) {
     case PRIMARY: {
-      err_code = restricted_token.GetRestrictedTokenHandle(token_handle);
+      err_code = restricted_token.GetRestrictedToken(token);
       break;
     }
     case IMPERSONATION: {
-      err_code = restricted_token.GetRestrictedTokenHandleForImpersonation(
-          token_handle);
+      err_code = restricted_token.GetRestrictedTokenForImpersonation(token);
       break;
     }
     default: {
@@ -140,99 +135,6 @@
   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) {
@@ -309,16 +211,17 @@
   if (!::ConvertStringSidToSid(integrity_level_str, &integrity_sid))
     return ::GetLastError();
 
-  TOKEN_MANDATORY_LABEL label = {0};
+  TOKEN_MANDATORY_LABEL label = {};
   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);
+  auto last_error = ::GetLastError();
   ::LocalFree(integrity_sid);
 
-  return result ? ERROR_SUCCESS : ::GetLastError();
+  return result ? ERROR_SUCCESS : last_error;
 }
 
 DWORD SetProcessIntegrityLevel(IntegrityLevel integrity_level) {
diff --git a/sandbox/win/src/restricted_token_utils.h b/sandbox/win/src/restricted_token_utils.h
index 509feaf..b4e4fde 100644
--- a/sandbox/win/src/restricted_token_utils.h
+++ b/sandbox/win/src/restricted_token_utils.h
@@ -8,6 +8,7 @@
 #include <accctrl.h>
 #include <windows.h>
 
+#include "base/win/scoped_handle.h"
 #include "sandbox/win/src/restricted_token.h"
 #include "sandbox/win/src/security_level.h"
 
@@ -27,41 +28,15 @@
 // 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.
+// |token| 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,
+DWORD CreateRestrictedToken(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);
+                            TokenType token_type,
+                            base::win::ScopedHandle* token);
 
 // Sets the integrity label on a object handle.
 DWORD SetObjectIntegrityLabel(HANDLE handle, SE_OBJECT_TYPE type,
diff --git a/sandbox/win/src/sandbox_nt_util.cc b/sandbox/win/src/sandbox_nt_util.cc
index 64fd1f1..82de75c 100644
--- a/sandbox/win/src/sandbox_nt_util.cc
+++ b/sandbox/win/src/sandbox_nt_util.cc
@@ -4,6 +4,8 @@
 
 #include "sandbox/win/src/sandbox_nt_util.h"
 
+#include <string>
+
 #include "base/win/pe_image.h"
 #include "sandbox/win/src/sandbox_factory.h"
 #include "sandbox/win/src/target_services.h"
@@ -55,7 +57,7 @@
 
     // Try 100 MB higher.
     base = reinterpret_cast<char*>(base) + 100 * 0x100000;
-  };
+  }
 
   if (attempts == 41)
     return NULL;
@@ -74,7 +76,6 @@
 #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.
@@ -289,7 +290,8 @@
 
 // Hacky code... replace with AllocAndCopyObjectAttributes.
 NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object,
-                          wchar_t** out_name, uint32* attributes,
+                          wchar_t** out_name,
+                          uint32_t* attributes,
                           HANDLE* root) {
   if (!InitHeap())
     return STATUS_NO_MEMORY;
@@ -337,7 +339,7 @@
   return ret;
 }
 
-NTSTATUS GetProcessId(HANDLE process, ULONG *process_id) {
+NTSTATUS GetProcessId(HANDLE process, DWORD *process_id) {
   PROCESS_BASIC_INFORMATION proc_info;
   ULONG bytes_returned;
 
@@ -355,7 +357,7 @@
   if (NtCurrentProcess == process)
     return true;
 
-  static ULONG s_process_id = 0;
+  static DWORD s_process_id = 0;
 
   if (!s_process_id) {
     NTSTATUS ret = GetProcessId(NtCurrentProcess, &s_process_id);
@@ -363,7 +365,7 @@
       return false;
   }
 
-  ULONG process_id;
+  DWORD process_id;
   NTSTATUS ret = GetProcessId(process, &process_id);
   if (!NT_SUCCESS(ret))
     return false;
@@ -432,7 +434,7 @@
   return out_string;
 }
 
-UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32* flags) {
+UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32_t* flags) {
   // PEImage's dtor won't be run during SEH unwinding, but that's OK.
 #pragma warning(push)
 #pragma warning(disable: 4509)
@@ -528,7 +530,7 @@
 
   // Based on the code above, size_bytes should always be small enough
   // to make the static_cast below safe.
-  DCHECK_NT(kuint16max > size_bytes);
+  DCHECK_NT(UINT16_MAX > size_bytes);
   char* str_buffer = new(NT_ALLOC) char[size_bytes + sizeof(UNICODE_STRING)];
   if (!str_buffer)
     return NULL;
@@ -584,8 +586,9 @@
   return ret;
 }
 
-bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info, DWORD length,
-                           uint32 file_info_class) {
+bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info,
+                           DWORD length,
+                           uint32_t file_info_class) {
   if (FileRenameInformation != file_info_class)
     return false;
 
@@ -605,7 +608,7 @@
 
   // Check if it starts with \\??\\. We don't support relative paths.
   if (file_info->FileNameLength < sizeof(kPathPrefix) ||
-      file_info->FileNameLength > kuint16max)
+      file_info->FileNameLength > UINT16_MAX)
     return false;
 
   if (file_info->FileName[0] != kPathPrefix[0] ||
@@ -621,15 +624,13 @@
 
 void* operator new(size_t size, sandbox::AllocationType type,
                    void* near_to) {
-  using namespace sandbox;
-
   void* result = NULL;
-  if (NT_ALLOC == type) {
-    if (InitHeap()) {
+  if (type == sandbox::NT_ALLOC) {
+    if (sandbox::InitHeap()) {
       // Use default flags for the allocation.
-      result = g_nt.RtlAllocateHeap(sandbox::g_heap, 0, size);
+      result = sandbox::g_nt.RtlAllocateHeap(sandbox::g_heap, 0, size);
     }
-  } else if (NT_PAGE == type) {
+  } else if (type == sandbox::NT_PAGE) {
     result = AllocateNearTo(near_to, size);
   } else {
     NOTREACHED_NT();
@@ -643,37 +644,31 @@
 }
 
 void operator delete(void* memory, sandbox::AllocationType type) {
-  using namespace sandbox;
-
-  if (NT_ALLOC == type) {
+  if (type == sandbox::NT_ALLOC) {
     // Use default flags.
-    VERIFY(g_nt.RtlFreeHeap(sandbox::g_heap, 0, memory));
-  } else if (NT_PAGE == type) {
+    VERIFY(sandbox::g_nt.RtlFreeHeap(sandbox::g_heap, 0, memory));
+  } else if (type == sandbox::NT_PAGE) {
     void* base = memory;
     SIZE_T size = 0;
-    VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size,
-                                          MEM_RELEASE));
+    VERIFY_SUCCESS(sandbox::g_nt.FreeVirtualMemory(NtCurrentProcess, &base,
+                                                   &size, MEM_RELEASE));
   } else {
     NOTREACHED_NT();
   }
 }
 
-void operator delete(void* memory, sandbox::AllocationType type,
+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,
+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);
-}
+void __cdecl operator delete(void* memory,
+                             void* buffer,
+                             sandbox::AllocationType type) {}
diff --git a/sandbox/win/src/sandbox_nt_util.h b/sandbox/win/src/sandbox_nt_util.h
index 83dd7c0..3dee932 100644
--- a/sandbox/win/src/sandbox_nt_util.h
+++ b/sandbox/win/src/sandbox_nt_util.h
@@ -6,8 +6,9 @@
 #define SANDBOX_SRC_SANDBOX_NT_UTIL_H_
 
 #include <intrin.h>
+#include <stdint.h>
 
-#include "base/basictypes.h"
+#include "base/macros.h"
 #include "sandbox/win/src/nt_internals.h"
 #include "sandbox/win/src/sandbox_nt_types.h"
 
@@ -101,7 +102,9 @@
 
 // Copies the name from an object attributes.
 NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object,
-                          wchar_t** out_name, uint32* attributes, HANDLE* root);
+                          wchar_t** out_name,
+                          uint32_t* attributes,
+                          HANDLE* root);
 
 // Determine full path name from object root and path.
 NTSTATUS AllocAndGetFullPath(HANDLE root,
@@ -134,7 +137,7 @@
 // }
 // InsertYourLogicHere(name);
 // operator delete(name, NT_ALLOC);
-UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32* flags);
+UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32_t* 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
@@ -182,8 +185,9 @@
 
 // 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);
+bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info,
+                           DWORD length,
+                           uint32_t file_info_class);
 
 }  // namespace sandbox
 
diff --git a/sandbox/win/src/sandbox_nt_util_unittest.cc b/sandbox/win/src/sandbox_nt_util_unittest.cc
new file mode 100644
index 0000000..0fbea66
--- /dev/null
+++ b/sandbox/win/src/sandbox_nt_util_unittest.cc
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+namespace {
+
+TEST(SandboxNtUtil, IsSameProcessPseudoHandle) {
+  InitGlobalNt();
+
+  HANDLE current_process_pseudo = GetCurrentProcess();
+  EXPECT_TRUE(IsSameProcess(current_process_pseudo));
+}
+
+TEST(SandboxNtUtil, IsSameProcessNonPseudoHandle) {
+  InitGlobalNt();
+
+  base::win::ScopedHandle current_process(
+      OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()));
+  ASSERT_TRUE(current_process.IsValid());
+  EXPECT_TRUE(IsSameProcess(current_process.Get()));
+}
+
+TEST(SandboxNtUtil, IsSameProcessDifferentProcess) {
+  InitGlobalNt();
+
+  STARTUPINFO si = {sizeof(si)};
+  PROCESS_INFORMATION pi = {};
+  wchar_t notepad[] = L"notepad";
+  ASSERT_TRUE(CreateProcessW(nullptr, notepad, nullptr, nullptr, FALSE, 0,
+                             nullptr, nullptr, &si, &pi));
+  base::win::ScopedProcessInformation process_info(pi);
+
+  EXPECT_FALSE(IsSameProcess(process_info.process_handle()));
+  EXPECT_TRUE(TerminateProcess(process_info.process_handle(), 0));
+}
+
+}  // namespace
+}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index 54bb2a9..c1af857 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -75,7 +75,7 @@
   // 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
+  //   win32's RevertToSelf(). Once this happens the initial token is no longer
   //   available and the lockdown token is in effect. Using an initial token is
   //   not compatible with AppContainer, see SetAppContainer.
   // lockdown: the security level for the token that comes into force after the
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
index 81b1e6a..17f52c5 100644
--- a/sandbox/win/src/sandbox_policy_base.cc
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -9,6 +9,8 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/app_container.h"
 #include "sandbox/win/src/filesystem_dispatcher.h"
@@ -31,6 +33,7 @@
 #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/sandbox_utils.h"
 #include "sandbox/win/src/sync_dispatcher.h"
 #include "sandbox/win/src/sync_policy.h"
 #include "sandbox/win/src/target_process.h"
@@ -67,6 +70,43 @@
   return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
 }
 
+HANDLE CreateLowBoxObjectDirectory(PSID lowbox_sid) {
+  DWORD session_id = 0;
+  if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id))
+    return NULL;
+
+  LPWSTR sid_string = NULL;
+  if (!::ConvertSidToStringSid(lowbox_sid, &sid_string))
+    return NULL;
+
+  base::string16 directory_path = base::StringPrintf(
+                   L"\\Sessions\\%d\\AppContainerNamedObjects\\%ls",
+                   session_id, sid_string).c_str();
+  ::LocalFree(sid_string);
+
+  NtCreateDirectoryObjectFunction CreateObjectDirectory = NULL;
+  ResolveNTFunctionPtr("NtCreateDirectoryObject", &CreateObjectDirectory);
+
+  OBJECT_ATTRIBUTES obj_attr;
+  UNICODE_STRING obj_name;
+  sandbox::InitObjectAttribs(directory_path,
+                             OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+                             NULL,
+                             &obj_attr,
+                             &obj_name,
+                             NULL);
+
+  HANDLE handle = NULL;
+  NTSTATUS status = CreateObjectDirectory(&handle,
+                                          DIRECTORY_ALL_ACCESS,
+                                          &obj_attr);
+
+  if (!NT_SUCCESS(status))
+    return NULL;
+
+  return handle;
+}
+
 }
 
 namespace sandbox {
@@ -427,33 +467,26 @@
 
 void* PolicyBase::AddHandleToShare(HANDLE handle) {
   if (base::win::GetVersion() < base::win::VERSION_VISTA)
-    return NULL;
+    return nullptr;
 
   if (!handle)
-    return NULL;
+    return nullptr;
 
-  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);
+  HANDLE duped_handle = nullptr;
+  if (!::DuplicateHandle(::GetCurrentProcess(), handle, ::GetCurrentProcess(),
+                         &duped_handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+    return nullptr;
+  }
+  handles_to_share_.push_back(new base::win::ScopedHandle(duped_handle));
   return duped_handle;
 }
 
-HandleList PolicyBase::GetHandlesBeingShared() {
+const HandleList& PolicyBase::GetHandlesBeingShared() {
   return handles_to_share_;
 }
 
 void PolicyBase::ClearSharedHandles() {
-  for (auto handle : handles_to_share_) {
-    ::CloseHandle(handle);
-  }
-  handles_to_share_.clear();
+  STLDeleteElements(&handles_to_share_);
 }
 
 // When an IPC is ready in any of the targets we get called. We manage an array
@@ -462,8 +495,8 @@
 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};
+  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>(
@@ -492,23 +525,25 @@
   return dispatch->SetupService(manager, service);
 }
 
-ResultCode PolicyBase::MakeJobObject(HANDLE* job) {
+ResultCode PolicyBase::MakeJobObject(base::win::ScopedHandle* 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) {
+    if (ERROR_SUCCESS != result)
       return SBOX_ERROR_GENERIC;
-    }
-    *job = job_obj.Detach();
+
+    *job = job_obj.Take();
   } else {
-    *job = NULL;
+    *job = base::win::ScopedHandle();
   }
   return SBOX_ALL_OK;
 }
 
-ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) {
+ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
+                                  base::win::ScopedHandle* lockdown,
+                                  base::win::ScopedHandle* lowbox) {
   if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer() &&
       lowbox_sid_) {
     return SBOX_ERROR_BAD_PARAMS;
@@ -516,8 +551,8 @@
 
   // 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);
+  DWORD result = CreateRestrictedToken(lockdown_level_,  integrity_level_,
+                                       PRIMARY, lockdown);
   if (ERROR_SUCCESS != result)
     return SBOX_ERROR_GENERIC;
 
@@ -551,34 +586,45 @@
     if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
       return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
 
-    *initial = INVALID_HANDLE_VALUE;
+    *initial = base::win::ScopedHandle();
     return SBOX_ALL_OK;
-  } else if (lowbox_sid_) {
+  }
+
+  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,
+
+    if (!lowbox_directory_.IsValid())
+      lowbox_directory_.Set(CreateLowBoxObjectDirectory(lowbox_sid_));
+    DCHECK(lowbox_directory_.IsValid());
+
+    // The order of handles isn't important in the CreateLowBoxToken call.
+    // The kernel will maintain a reference to the object directory handle.
+    HANDLE saved_handles[1] = {lowbox_directory_.Get()};
+    DWORD saved_handles_count = lowbox_directory_.IsValid() ? 1 : 0;
+
+    NTSTATUS status = CreateLowBoxToken(&token_lowbox, lockdown->Get(),
                                         TOKEN_ALL_ACCESS, &obj_attr,
-                                        lowbox_sid_, 0, NULL, 0, NULL);
+                                        lowbox_sid_, 0, NULL,
+                                        saved_handles_count, saved_handles);
     if (!NT_SUCCESS(status))
       return SBOX_ERROR_GENERIC;
 
     DCHECK(token_lowbox);
-    ::CloseHandle(*lockdown);
-    *lockdown = token_lowbox;
+    lowbox->Set(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);
+  result = CreateRestrictedToken(initial_level_, integrity_level_,
+                                 IMPERSONATION, initial);
+  if (ERROR_SUCCESS != result)
     return SBOX_ERROR_GENERIC;
-  }
+
   return SBOX_ALL_OK;
 }
 
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index 136e3a4..a461bd7 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -13,6 +13,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/strings/string16.h"
+#include "base/win/scoped_handle.h"
 #include "sandbox/win/src/crosscall_server.h"
 #include "sandbox/win/src/handle_closer.h"
 #include "sandbox/win/src/ipc_tags.h"
@@ -28,7 +29,7 @@
 class TargetProcess;
 struct PolicyGlobal;
 
-typedef std::vector<HANDLE> HandleList;
+typedef std::vector<base::win::ScopedHandle*> 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.
@@ -78,11 +79,14 @@
 
   // Creates a Job object with the level specified in a previous call to
   // SetJobLevel().
-  ResultCode MakeJobObject(HANDLE* job);
+  ResultCode MakeJobObject(base::win::ScopedHandle* job);
 
   // Creates the two tokens with the levels specified in a previous call to
-  // SetTokenLevel().
-  ResultCode MakeTokens(HANDLE* initial, HANDLE* lockdown);
+  // SetTokenLevel(). Also creates a lowbox token if specified based on the
+  // lowbox SID.
+  ResultCode MakeTokens(base::win::ScopedHandle* initial,
+                        base::win::ScopedHandle* lockdown,
+                        base::win::ScopedHandle* lowbox);
 
   const AppContainerAttributes* GetAppContainer() const;
 
@@ -103,7 +107,7 @@
   HANDLE GetStderrHandle();
 
   // Returns the list of handles being shared with the target process.
-  HandleList GetHandlesBeingShared();
+  const HandleList& GetHandlesBeingShared();
 
   // Closes the handles being shared with the target and clears out the list.
   void ClearSharedHandles();
@@ -167,6 +171,7 @@
   std::vector<base::string16> capabilities_;
   scoped_ptr<AppContainerAttributes> appcontainer_list_;
   PSID lowbox_sid_;
+  base::win::ScopedHandle lowbox_directory_;
 
   static HDESK alternate_desktop_handle_;
   static HWINSTA alternate_winstation_handle_;
@@ -175,7 +180,7 @@
   // 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_;
+  HandleList handles_to_share_;
 
   DISALLOW_COPY_AND_ASSIGN(PolicyBase);
 };
diff --git a/sandbox/win/src/sandbox_rand.cc b/sandbox/win/src/sandbox_rand.cc
new file mode 100644
index 0000000..b3f9773
--- /dev/null
+++ b/sandbox/win/src/sandbox_rand.cc
@@ -0,0 +1,22 @@
+// 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 "sandbox/win/src/sandbox_rand.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
+
+namespace sandbox {
+
+bool GetRandom(unsigned int* random_value) {
+  return RtlGenRandom(random_value, sizeof(unsigned int)) != FALSE;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_rand.h b/sandbox/win/src/sandbox_rand.h
new file mode 100644
index 0000000..7f48287
--- /dev/null
+++ b/sandbox/win/src/sandbox_rand.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_RAND_H_
+#define SANDBOX_SRC_SANDBOX_RAND_H_
+
+#include "base/basictypes.h"
+
+namespace sandbox {
+
+// Generate a random value in |random_value|. Returns true on success.
+bool GetRandom(unsigned int* random_value);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SANDBOX_RAND_H_
diff --git a/sandbox/win/src/service_resolver.h b/sandbox/win/src/service_resolver.h
index ab125fb..08a45ba 100644
--- a/sandbox/win/src/service_resolver.h
+++ b/sandbox/win/src/service_resolver.h
@@ -5,6 +5,7 @@
 #ifndef SANDBOX_SRC_SERVICE_RESOLVER_H__
 #define SANDBOX_SRC_SERVICE_RESOLVER_H__
 
+#include "base/macros.h"
 #include "sandbox/win/src/nt_internals.h"
 #include "sandbox/win/src/resolver.h"
 
@@ -16,8 +17,10 @@
  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) {}
+      : ntdll_base_(NULL),
+        process_(process),
+        relaxed_(relaxed),
+        relative_jump_(0) {}
   ~ServiceResolverThunk() override {}
 
   // Implementation of Resolver::Setup.
@@ -133,6 +136,21 @@
   DISALLOW_COPY_AND_ASSIGN(Win8ResolverThunk);
 };
 
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll on WOW64 for Windows 10.
+class Wow64W10ResolverThunk : public ServiceResolverThunk {
+ public:
+  // The service resolver needs a child process to write to.
+  Wow64W10ResolverThunk(HANDLE process, bool relaxed)
+      : ServiceResolverThunk(process, relaxed) {}
+  ~Wow64W10ResolverThunk() override {}
+
+ private:
+  bool IsFunctionAService(void* local_thunk) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(Wow64W10ResolverThunk);
+};
+
 }  // namespace sandbox
 
 
diff --git a/sandbox/win/src/service_resolver_32.cc b/sandbox/win/src/service_resolver_32.cc
index ab69ab8..b0c6ca6 100644
--- a/sandbox/win/src/service_resolver_32.cc
+++ b/sandbox/win/src/service_resolver_32.cc
@@ -18,7 +18,6 @@
 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;
@@ -30,8 +29,6 @@
 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 {
@@ -121,6 +118,21 @@
   BYTE nop;
 };
 
+// Service code for a 32 bit process running on 64 bit Windows 10.
+struct Wow64EntryW10 {
+  // 00 b828000000      mov     eax, 28h
+  // 05 bab0d54877      mov     edx, 7748D5B0h
+  // 09 ffd2            call    edx
+  // 0b c22800          ret     28h
+  BYTE mov_eax;         // = B8
+  ULONG service_id;
+  BYTE mov_edx;         // = BA
+  ULONG mov_edx_param;
+  USHORT call_edx;      // = FF D2
+  BYTE ret;             // = C2
+  USHORT num_params;
+};
+
 // Make sure that relaxed patching works as expected.
 const size_t kMinServiceSize = offsetof(ServiceEntry, ret);
 static_assert(sizeof(ServiceEntryW8) >= kMinServiceSize,
@@ -165,8 +177,9 @@
                                 thunk_buffer.get());
 
   if (!IsFunctionAService(&thunk->original) &&
-      (!relaxed_ || !SaveOriginalFunction(&thunk->original, thunk_storage)))
+      (!relaxed_ || !SaveOriginalFunction(&thunk->original, thunk_storage))) {
     return STATUS_UNSUCCESSFUL;
+  }
 
   ret = PerformPatch(thunk, thunk_storage);
 
@@ -210,8 +223,9 @@
   ServiceEntry function_code;
   SIZE_T read;
   if (!::ReadProcessMemory(process_, target_, &function_code,
-                           sizeof(function_code), &read))
+                           sizeof(function_code), &read)) {
     return false;
+  }
 
   if (sizeof(function_code) != read)
     return false;
@@ -220,16 +234,18 @@
       kMovEdx != function_code.mov_edx ||
       (kCallPtrEdx != function_code.call_ptr_edx &&
        kCallEdx != function_code.call_ptr_edx) ||
-      kRet != function_code.ret)
+      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))
+                             &ki_system_call, sizeof(ki_system_call), &read)) {
       return false;
+    }
 
     if (sizeof(ki_system_call) != read)
       return false;
@@ -238,8 +254,10 @@
     // 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))
+                           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
@@ -297,8 +315,9 @@
   // copy the local thunk buffer to the child
   SIZE_T written;
   if (!::WriteProcessMemory(process_, remote_thunk, local_thunk,
-                            thunk_size, &written))
+                            thunk_size, &written)) {
     return STATUS_UNSUCCESSFUL;
+  }
 
   if (thunk_size != written)
     return STATUS_UNSUCCESSFUL;
@@ -323,8 +342,9 @@
   ServiceEntry function_code;
   SIZE_T read;
   if (!::ReadProcessMemory(process_, target_, &function_code,
-                           sizeof(function_code), &read))
+                           sizeof(function_code), &read)) {
     return false;
+  }
 
   if (sizeof(function_code) != read)
     return false;
@@ -358,16 +378,19 @@
   Wow64Entry function_code;
   SIZE_T read;
   if (!::ReadProcessMemory(process_, target_, &function_code,
-                           sizeof(function_code), &read))
+                           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)
+      kCallFs2 != function_code.call_fs2 ||
+      kCallFs3 != function_code.call_fs3) {
     return false;
+  }
 
   if ((kAddEsp1 == function_code.add_esp1 &&
        kAddEsp2 == function_code.add_esp2 &&
@@ -384,8 +407,9 @@
   Wow64EntryW8 function_code;
   SIZE_T read;
   if (!::ReadProcessMemory(process_, target_, &function_code,
-                           sizeof(function_code), &read))
+                           sizeof(function_code), &read)) {
     return false;
+  }
 
   if (sizeof(function_code) != read)
     return false;
@@ -405,8 +429,9 @@
   ServiceEntryW8 function_code;
   SIZE_T read;
   if (!::ReadProcessMemory(process_, target_, &function_code,
-                           sizeof(function_code), &read))
+                           sizeof(function_code), &read)) {
     return false;
+  }
 
   if (sizeof(function_code) != read)
     return false;
@@ -424,4 +449,27 @@
   return true;
 }
 
+bool Wow64W10ResolverThunk::IsFunctionAService(void* local_thunk) const {
+  Wow64EntryW10 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 ||
+      kCallEdx != function_code.call_edx ||
+      kRet != 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
index 984cb38..c0e684c 100644
--- a/sandbox/win/src/service_resolver_64.cc
+++ b/sandbox/win/src/service_resolver_64.cc
@@ -17,6 +17,10 @@
 const ULONG64 kMov1 = 0x54894808244C8948;
 const ULONG64 kMov2 = 0x4C182444894C1024;
 const ULONG kMov3 = 0x20244C89;
+const USHORT kTestByte = 0x04F6;
+const BYTE kPtr = 0x25;
+const BYTE kRet = 0xC3;
+const USHORT kJne = 0x0375;
 
 // Service code for 64 bit systems.
 struct ServiceEntry {
@@ -60,11 +64,37 @@
   BYTE nop;                   // = 90
 };
 
+// Service code for 64 bit systems with int 2e fallback.
+struct ServiceEntryWithInt2E {
+  // This struct contains roughly the following code:
+  // 00 4c8bd1           mov     r10,rcx
+  // 03 b855000000       mov     eax,52h
+  // 08 f604250803fe7f01 test byte ptr SharedUserData!308, 1
+  // 10 7503             jne [over syscall]
+  // 12 0f05             syscall
+  // 14 c3               ret
+  // 15 cd2e             int 2e
+  // 17 c3               ret
+
+  ULONG mov_r10_rcx_mov_eax;  // = 4C 8B D1 B8
+  ULONG service_id;
+  USHORT test_byte;           // = F6 04
+  BYTE ptr;                   // = 25
+  ULONG user_shared_data_ptr;
+  BYTE one;                   // = 01
+  USHORT jne_over_syscall;    // = 75 03
+  USHORT syscall;             // = 0F 05
+  BYTE ret;                   // = C3
+  USHORT int2e;               // = CD 2E
+  BYTE ret2;                  // = C3
+};
+
 // We don't have an internal thunk for x64.
 struct ServiceFullThunk {
   union {
     ServiceEntry original;
     ServiceEntryW8 original_w8;
+    ServiceEntryWithInt2E original_int2e_fallback;
   };
 };
 
@@ -78,6 +108,25 @@
           kSyscall == service->syscall && kRetNp == service->ret);
 }
 
+bool IsServiceW8(const void* source) {
+  const ServiceEntryW8* service =
+      reinterpret_cast<const ServiceEntryW8*>(source);
+
+  return (kMmovR10EcxMovEax == service->mov_r10_rcx_mov_eax &&
+          kMov1 == service->mov_1 && kMov2 == service->mov_2 &&
+          kMov3 == service->mov_3);
+}
+
+bool IsServiceWithInt2E(const void* source) {
+  const ServiceEntryWithInt2E* service =
+      reinterpret_cast<const ServiceEntryWithInt2E*>(source);
+
+  return (kMmovR10EcxMovEax == service->mov_r10_rcx_mov_eax &&
+          kTestByte == service->test_byte && kPtr == service->ptr &&
+          kJne == service->jne_over_syscall && kSyscall == service->syscall &&
+          kRet == service->ret && kRet == service->ret2);
+}
+
 };  // namespace
 
 namespace sandbox {
@@ -150,15 +199,9 @@
   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;
-    }
-  }
+  if (!IsService(&function_code) && !IsServiceW8(&function_code) &&
+      !IsServiceWithInt2E(&function_code))
+    return false;
 
   // Save the verified code.
   memcpy(local_thunk, &function_code, sizeof(function_code));
diff --git a/sandbox/win/src/service_resolver_unittest.cc b/sandbox/win/src/service_resolver_unittest.cc
index c7ac7ea..2ae3e47 100644
--- a/sandbox/win/src/service_resolver_unittest.cc
+++ b/sandbox/win/src/service_resolver_unittest.cc
@@ -38,12 +38,12 @@
                         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);
+    ret = T::Init(target_module, interceptor_module, target_name,
+                  interceptor_name, interceptor_entry_point, thunk_storage,
+                  storage_bytes);
     EXPECT_EQ(STATUS_SUCCESS, ret);
 
-    target_ = fake_target_;
+    this->target_ = fake_target_;
 
     return ret;
   };
@@ -61,6 +61,7 @@
 typedef ResolverThunkTest<sandbox::Win8ResolverThunk> Win8ResolverTest;
 typedef ResolverThunkTest<sandbox::Wow64ResolverThunk> Wow64ResolverTest;
 typedef ResolverThunkTest<sandbox::Wow64W8ResolverThunk> Wow64W8ResolverTest;
+typedef ResolverThunkTest<sandbox::Wow64W10ResolverThunk> Wow64W10ResolverTest;
 #endif
 
 const BYTE kJump32 = 0xE9;
@@ -135,6 +136,8 @@
 #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_WIN10)
+      return new Wow64W10ResolverTest(relaxed);
     if (os_info->version() >= base::win::VERSION_WIN8)
       return new Wow64W8ResolverTest(relaxed);
     return new Wow64ResolverTest(relaxed);
diff --git a/sandbox/win/src/shared_handles.cc b/sandbox/win/src/shared_handles.cc
deleted file mode 100644
index 423b67b..0000000
--- a/sandbox/win/src/shared_handles.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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
deleted file mode 100644
index 2c76bfb..0000000
--- a/sandbox/win/src/shared_handles.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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
index fa6a877..8f79109 100644
--- a/sandbox/win/src/sharedmem_ipc_client.cc
+++ b/sandbox/win/src/sharedmem_ipc_client.cc
@@ -32,7 +32,6 @@
   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
diff --git a/sandbox/win/src/sharedmem_ipc_server.cc b/sandbox/win/src/sharedmem_ipc_server.cc
index 5ce7da5..ea1793c 100644
--- a/sandbox/win/src/sharedmem_ipc_server.cc
+++ b/sandbox/win/src/sharedmem_ipc_server.cc
@@ -5,6 +5,7 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
 #include "sandbox/win/src/sharedmem_ipc_server.h"
 #include "sandbox/win/src/sharedmem_ipc_client.h"
 #include "sandbox/win/src/sandbox.h"
@@ -19,16 +20,20 @@
 
 namespace sandbox {
 
+SharedMemIPCServer::ServerControl::ServerControl() {
+}
+
+SharedMemIPCServer::ServerControl::~ServerControl() {
+}
+
 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
@@ -51,14 +56,7 @@
     // 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;
-  }
+  STLDeleteElements(&server_contexts_);
 
   if (client_control_)
     ::UnmapViewOfFile(client_control_);
@@ -111,9 +109,11 @@
     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)
+    // 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). In particular, target_process_
+    // is a raw handle that is not owned by this object (it's owned by the
+    // owner of this object), and we are storing it in multiple places.
     service_context->shared_base = reinterpret_cast<char*>(shared_mem);
     service_context->channel_size = channel_size;
     service_context->channel = client_context;
@@ -122,11 +122,10 @@
     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,
+    thread_provider_->RegisterWait(this, service_context->ping_event.Get(),
                                    ThreadPingEventReady, service_context);
   }
   if (!::DuplicateHandle(::GetCurrentProcess(), g_alive_mutex,
@@ -397,24 +396,28 @@
   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);
+  ::SetEvent(service_context->pong_event.Get());
 }
 
-bool SharedMemIPCServer::MakeEvents(HANDLE* server_ping, HANDLE* server_pong,
+bool SharedMemIPCServer::MakeEvents(base::win::ScopedHandle* server_ping,
+                                    base::win::ScopedHandle* 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)) {
+  server_ping->Set(::CreateEventW(NULL, FALSE, FALSE, NULL));
+  if (!::DuplicateHandle(::GetCurrentProcess(), server_ping->Get(),
+                         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)) {
+
+  server_pong->Set(::CreateEventW(NULL, FALSE, FALSE, NULL));
+  if (!::DuplicateHandle(::GetCurrentProcess(), server_pong->Get(),
+                         target_process_, client_pong, kDesiredAccess, FALSE,
+                         0)) {
     return false;
   }
   return true;
diff --git a/sandbox/win/src/sharedmem_ipc_server.h b/sandbox/win/src/sharedmem_ipc_server.h
index 94d6959..cb40bca 100644
--- a/sandbox/win/src/sharedmem_ipc_server.h
+++ b/sandbox/win/src/sharedmem_ipc_server.h
@@ -9,6 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/gtest_prod_util.h"
+#include "base/win/scoped_handle.h"
 #include "sandbox/win/src/crosscall_params.h"
 #include "sandbox/win/src/crosscall_server.h"
 #include "sandbox/win/src/sharedmem_ipc_client.h"
@@ -36,14 +37,17 @@
 class SharedMemIPCServer {
  public:
   // Creates the IPC server.
-  // target_process: handle to the target process. It must be suspended.
+  // target_process: handle to the target process. It must be suspended. It is
+  // unfortunate to receive a raw handle (and store it inside this object) as
+  // that dilutes ownership of the process, but in practice a SharedMemIPCServer
+  // is owned by TargetProcess, which calls this method, and owns the handle, so
+  // everything is safe. If that changes, we should break this dependency and
+  // duplicate the handle instead.
   // 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);
+                     ThreadProvider* thread_provider, Dispatcher* dispatcher);
 
   ~SharedMemIPCServer();
 
@@ -63,7 +67,8 @@
 
   // Makes the client and server events. This function is called once
   // per channel.
-  bool MakeEvents(HANDLE* server_ping, HANDLE* server_pong,
+  bool MakeEvents(base::win::ScopedHandle* server_ping,
+                  base::win::ScopedHandle* server_pong,
                   HANDLE* client_ping, HANDLE* client_pong);
 
   // A copy this structure is maintained per channel.
@@ -72,10 +77,13 @@
   // static method without worrying about converting back to a member function
   // call or about threading issues.
   struct ServerControl {
+    ServerControl();
+    ~ServerControl();
+
     // This channel server ping event.
-    HANDLE ping_event;
+    base::win::ScopedHandle ping_event;
     // This channel server pong event.
-    HANDLE pong_event;
+    base::win::ScopedHandle pong_event;
     // The size of this channel.
     uint32 channel_size;
     // The pointer to the actual channel data.
@@ -113,9 +121,6 @@
   // 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_;
 
diff --git a/sandbox/win/src/sync_dispatcher.cc b/sandbox/win/src/sync_dispatcher.cc
index b83055d..a638d3d 100644
--- a/sandbox/win/src/sync_dispatcher.cc
+++ b/sandbox/win/src/sync_dispatcher.cc
@@ -20,14 +20,12 @@
 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)
-  };
+      {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_OPENEVENT_TAG, {WCHAR_TYPE, UINT32_TYPE}},
+      reinterpret_cast<CallbackGeneric>(&SyncDispatcher::OpenEvent)};
 
   ipc_calls_.push_back(create_params);
   ipc_calls_.push_back(open_params);
diff --git a/sandbox/win/src/sync_policy.cc b/sandbox/win/src/sync_policy.cc
index 607b446..379e8f4 100644
--- a/sandbox/win/src/sync_policy.cc
+++ b/sandbox/win/src/sync_policy.cc
@@ -47,11 +47,8 @@
   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;
+  if (!NT_SUCCESS(status))
     return status;
-  }
 
   OBJECT_ATTRIBUTES symbolic_link_attributes = {};
   UNICODE_STRING name_string = {};
@@ -61,20 +58,16 @@
   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;
+  CHECK(NT_SUCCESS(NtClose(symbolic_link_directory)));
+  if (!NT_SUCCESS(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;
+    CHECK(NT_SUCCESS(NtClose(symbolic_link)));
     return status;
   }
 
@@ -83,13 +76,10 @@
   target_path.Buffer = new wchar_t[target_path.MaximumLength + 1];
   status = NtQuerySymbolicLinkObject(symbolic_link, &target_path,
                                      &target_length);
-  if (status == STATUS_SUCCESS) {
+  if (NT_SUCCESS(status))
     target->assign(target_path.Buffer, target_length);
-  } else {
-    DLOG(ERROR) << "Failed to resolve symbolic link. Error: " << status;
-  }
 
-  NtClose(symbolic_link);
+  CHECK(NT_SUCCESS(NtClose(symbolic_link)));
   delete[] target_path.Buffer;
   return status;
 }
@@ -112,7 +102,7 @@
   NTSTATUS status = ResolveSymbolicLink(L"\\Sessions\\BNOLINKS",
                                         base::StringPrintf(L"%d", session_id),
                                         &base_named_objects_path);
-  if (status != STATUS_SUCCESS) {
+  if (!NT_SUCCESS(status)) {
     DLOG(ERROR) << "Failed to resolve BaseNamedObjects path. Error: "
                 << status;
     return status;
@@ -125,7 +115,7 @@
   status = NtOpenDirectoryObject(&base_named_objects_handle,
                                  DIRECTORY_ALL_ACCESS,
                                  &object_attributes);
-  if (status == STATUS_SUCCESS)
+  if (NT_SUCCESS(status))
     *directory = base_named_objects_handle;
   return status;
 }
diff --git a/sandbox/win/src/sync_policy_test.cc b/sandbox/win/src/sync_policy_test.cc
index 9fc08f4..875bc4b 100644
--- a/sandbox/win/src/sync_policy_test.cc
+++ b/sandbox/win/src/sync_policy_test.cc
@@ -72,9 +72,10 @@
     if (event_open.IsValid() && event_create.IsValid())
       return SBOX_TEST_SUCCEEDED;
 
-    if (event_open.IsValid() && !event_create.IsValid() ||
-        !event_open.IsValid() && event_create.IsValid())
+    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())
@@ -89,7 +90,7 @@
 }
 
 // Tests the creation of events using all the possible combinations.
-TEST(SyncPolicyTest, DISABLED_TestEvent) {
+TEST(SyncPolicyTest, TestEvent) {
   TestRunner runner;
   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
                              TargetPolicy::EVENTS_ALLOW_ANY,
@@ -113,7 +114,7 @@
 }
 
 // Tests opening events with read only access.
-TEST(SyncPolicyTest, DISABLED_TestEventReadOnly) {
+TEST(SyncPolicyTest, TestEventReadOnly) {
   TestRunner runner;
   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
                              TargetPolicy::EVENTS_ALLOW_READONLY,
diff --git a/sandbox/win/src/target_process.cc b/sandbox/win/src/target_process.cc
index e0284c3..69dce20 100644
--- a/sandbox/win/src/target_process.cc
+++ b/sandbox/win/src/target_process.cc
@@ -5,6 +5,7 @@
 #include "sandbox/win/src/target_process.h"
 
 #include "base/basictypes.h"
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/win/pe_image.h"
 #include "base/win/startup_information.h"
@@ -36,7 +37,7 @@
   }
 }
 
-}
+}  // namespace
 
 namespace sandbox {
 
@@ -64,18 +65,20 @@
   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),
+TargetProcess::TargetProcess(base::win::ScopedHandle initial_token,
+                             base::win::ScopedHandle lockdown_token,
+                             base::win::ScopedHandle lowbox_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.Pass()),
+      initial_token_(initial_token.Pass()),
+      lowbox_token_(lowbox_token.Pass()),
       job_(job),
       thread_pool_(thread_pool),
-      base_address_(NULL) {
-}
+      base_address_(NULL) {}
 
 TargetProcess::~TargetProcess() {
   DWORD exit_code = 0;
@@ -98,7 +101,7 @@
       // that.
       if (shared_section_.IsValid())
         shared_section_.Take();
-      ipc_server_.release();
+      ignore_result(ipc_server_.release());
       sandbox_process_info_.TakeProcessHandle();
       return;
     }
@@ -114,12 +117,11 @@
 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 &&
+  if (lowbox_token_.IsValid() &&
       base::win::GetVersion() < base::win::VERSION_WIN8) {
-    // We don't allow set_lockdown_token_after_create below Windows 8.
+    // We don't allow lowbox_token below Windows 8.
     return ERROR_INVALID_PARAMETER;
   }
 
@@ -141,38 +143,16 @@
     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();
-    }
+  if (!::CreateProcessAsUserW(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);
 
@@ -202,26 +182,6 @@
     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)) {
@@ -246,6 +206,25 @@
     return win_result;
   }
 
+  if (lowbox_token_.IsValid()) {
+    PROCESS_ACCESS_TOKEN process_access_token;
+    process_access_token.thread = process_info.thread_handle();
+    process_access_token.token = lowbox_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 = ERROR_INVALID_TOKEN;
+      ::TerminateProcess(process_info.process_handle(), 0);  // exit code
+      return win_result;
+    }
+  }
+
   base_address_ = GetBaseAddress(exe_path, entry_point);
   sandbox_process_info_.Set(process_info.Take());
   return win_result;
@@ -272,8 +251,6 @@
   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;
@@ -355,7 +332,7 @@
   ipc_server_.reset(
       new SharedMemIPCServer(sandbox_process_info_.process_handle(),
                              sandbox_process_info_.process_id(),
-                             job_, thread_pool_, ipc_dispatcher));
+                             thread_pool_, ipc_dispatcher));
 
   if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize))
     return ERROR_NOT_ENOUGH_MEMORY;
@@ -374,7 +351,9 @@
 }
 
 TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) {
-  TargetProcess* target = new TargetProcess(NULL, NULL, NULL, NULL);
+  TargetProcess* target =
+      new TargetProcess(base::win::ScopedHandle(), base::win::ScopedHandle(),
+                        base::win::ScopedHandle(), NULL, NULL);
   PROCESS_INFORMATION process_info = {};
   process_info.hProcess = process;
   target->sandbox_process_info_.Set(process_info);
diff --git a/sandbox/win/src/target_process.h b/sandbox/win/src/target_process.h
index cf5ad9f..59e6aea 100644
--- a/sandbox/win/src/target_process.h
+++ b/sandbox/win/src/target_process.h
@@ -32,8 +32,12 @@
 // 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,
+  // The constructor takes ownership of |initial_token|, |lockdown_token|
+  // and |lowbox_token|.
+  TargetProcess(base::win::ScopedHandle initial_token,
+                base::win::ScopedHandle lockdown_token,
+                base::win::ScopedHandle lowbox_token,
+                HANDLE job,
                 ThreadProvider* thread_pool);
   ~TargetProcess();
 
@@ -45,12 +49,9 @@
   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);
 
@@ -105,6 +106,9 @@
   // 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_;
+  // The lowbox token associated with the process. This token is set after the
+  // process creation.
+  base::win::ScopedHandle lowbox_token_;
   // Kernel handle to the shared memory used by the IPC server.
   base::win::ScopedHandle shared_section_;
   // Job object containing the target process.
diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc
index b43a3b8..116f0c9 100644
--- a/sandbox/win/src/target_services.cc
+++ b/sandbox/win/src/target_services.cc
@@ -4,6 +4,8 @@
 
 #include "sandbox/win/src/target_services.h"
 
+#include <new>
+
 #include <process.h>
 
 #include "base/basictypes.h"
@@ -45,11 +47,11 @@
 }
 
 // Checks if we have handle entries pending and runs the closer.
-bool CloseOpenHandles() {
+// Updates is_csrss_connected based on which handle types are closed.
+bool CloseOpenHandles(bool* is_csrss_connected) {
   if (sandbox::HandleCloserAgent::NeedsHandlesClosed()) {
     sandbox::HandleCloserAgent handle_closer;
-
-    handle_closer.InitializeHandlesToClose();
+    handle_closer.InitializeHandlesToClose(is_csrss_connected);
     if (!handle_closer.CloseHandles())
       return false;
   }
@@ -57,6 +59,14 @@
   return true;
 }
 
+
+// Used as storage for g_target_services, because other allocation facilities
+// are not available early. We can't use a regular function static because on
+// VS2015, because the CRT tries to acquire a lock to guard initialization, but
+// this code runs before the CRT is initialized.
+char g_target_services_memory[sizeof(sandbox::TargetServicesBase)];
+sandbox::TargetServicesBase* g_target_services = nullptr;
+
 }  // namespace
 
 namespace sandbox {
@@ -87,8 +97,10 @@
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_FLUSHANDLES);
   if (ERROR_SUCCESS != ::RegDisablePredefinedCache())
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE);
-  if (!CloseOpenHandles())
+  bool is_csrss_connected = true;
+  if (!CloseOpenHandles(&is_csrss_connected))
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES);
+  process_state_.SetCsrssConnected(is_csrss_connected);
   // Enabling mitigations must happen last otherwise handle closing breaks
   if (g_shared_delayed_mitigations &&
       !ApplyProcessMitigationsToCurrentProcess(g_shared_delayed_mitigations))
@@ -100,8 +112,10 @@
 }
 
 TargetServicesBase* TargetServicesBase::GetInstance() {
-  static TargetServicesBase instance;
-  return &instance;
+  // Leak on purpose TargetServicesBase.
+  if (!g_target_services)
+    g_target_services = new (g_target_services_memory) TargetServicesBase;
+  return g_target_services;
 }
 
 // The broker services a 'test' IPC service with the IPC_PING_TAG tag.
@@ -156,18 +170,25 @@
   return true;
 }
 
-bool ProcessState::IsKernel32Loaded() {
+ProcessState::ProcessState() : process_state_(0), csrss_connected_(true) {
+}
+
+bool ProcessState::IsKernel32Loaded() const {
   return process_state_ != 0;
 }
 
-bool ProcessState::InitCalled() {
+bool ProcessState::InitCalled() const {
   return process_state_ > 1;
 }
 
-bool ProcessState::RevertedToSelf() {
+bool ProcessState::RevertedToSelf() const {
   return process_state_ > 2;
 }
 
+bool ProcessState::IsCsrssConnected() const {
+  return csrss_connected_;
+}
+
 void ProcessState::SetKernel32Loaded() {
   if (!process_state_)
     process_state_ = 1;
@@ -183,6 +204,11 @@
     process_state_ = 3;
 }
 
+void ProcessState::SetCsrssConnected(bool csrss_connected) {
+  csrss_connected_ = csrss_connected;
+}
+
+
 ResultCode TargetServicesBase::DuplicateHandle(HANDLE source_handle,
                                                DWORD target_process_id,
                                                HANDLE* target_handle,
diff --git a/sandbox/win/src/target_services.h b/sandbox/win/src/target_services.h
index 115de46..c80a90d 100644
--- a/sandbox/win/src/target_services.h
+++ b/sandbox/win/src/target_services.h
@@ -13,24 +13,24 @@
 
 class ProcessState {
  public:
-  ProcessState() : process_state_(0) {}
-
+  ProcessState();
   // Returns true if kernel32.dll has been loaded.
-  bool IsKernel32Loaded();
-
+  bool IsKernel32Loaded() const;
   // Returns true if main has been called.
-  bool InitCalled();
-
+  bool InitCalled() const;
   // Returns true if LowerToken has been called.
-  bool RevertedToSelf();
-
+  bool RevertedToSelf() const;
+  // Returns true if Csrss is connected.
+  bool IsCsrssConnected() const;
   // Set the current state.
   void SetKernel32Loaded();
   void SetInitCalled();
   void SetRevertedToSelf();
+  void SetCsrssConnected(bool csrss_connected);
 
- public:
+ private:
   int process_state_;
+  bool csrss_connected_;
   DISALLOW_COPY_AND_ASSIGN(ProcessState);
 };
 
diff --git a/sandbox/win/src/unload_dll_test.cc b/sandbox/win/src/unload_dll_test.cc
index 620016c..7e398f6 100644
--- a/sandbox/win/src/unload_dll_test.cc
+++ b/sandbox/win/src/unload_dll_test.cc
@@ -40,8 +40,7 @@
   return event_open.Get() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
 }
 
-// Flaky on windows, see http://crbug.com/80569.
-TEST(UnloadDllTest, DISABLED_BaselineAvicapDll) {
+TEST(UnloadDllTest, BaselineAvicapDll) {
   TestRunner runner;
   runner.SetTestState(BEFORE_REVERT);
   runner.SetTimeout(2000);
@@ -56,8 +55,7 @@
   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"UseOneDLL B avicap32.dll"));
 }
 
-// Flaky on windows, see http://crbug.com/80569.
-TEST(UnloadDllTest, DISABLED_UnloadAviCapDllNoPatching) {
+TEST(UnloadDllTest, UnloadAviCapDllNoPatching) {
   TestRunner runner;
   runner.SetTestState(BEFORE_REVERT);
   runner.SetTimeout(2000);
@@ -67,8 +65,7 @@
   EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"UseOneDLL B avicap32.dll"));
 }
 
-// Flaky: http://crbug.com/38404
-TEST(UnloadDllTest, DISABLED_UnloadAviCapDllWithPatching) {
+TEST(UnloadDllTest, UnloadAviCapDllWithPatching) {
   TestRunner runner;
   runner.SetTimeout(2000);
   runner.SetTestState(BEFORE_REVERT);
diff --git a/sandbox/win/src/win_utils.cc b/sandbox/win/src/win_utils.cc
index 2ff1b73..e09c680 100644
--- a/sandbox/win/src/win_utils.cc
+++ b/sandbox/win/src/win_utils.cc
@@ -156,12 +156,10 @@
 //    \??\c:\some\foo\bar
 //    \Device\HarddiskVolume0\some\foo\bar
 //    \??\HarddiskVolume0\some\foo\bar
-DWORD IsReparsePoint(const base::string16& full_path, bool* result) {
+DWORD IsReparsePoint(const base::string16& full_path) {
   // Check if it's a pipe. We can't query the attributes of a pipe.
-  if (IsPipe(full_path)) {
-    *result = FALSE;
-    return ERROR_SUCCESS;
-  }
+  if (IsPipe(full_path))
+    return ERROR_NOT_A_REPARSE_POINT;
 
   base::string16 path;
   bool nt_path = IsNTPath(full_path, &path);
@@ -199,7 +197,6 @@
       }
     } else if (FILE_ATTRIBUTE_REPARSE_POINT & attributes) {
       // This is a reparse point.
-      *result = true;
       return ERROR_SUCCESS;
     }
 
@@ -207,8 +204,7 @@
     last_pos = path.rfind(L'\\');
   } while (last_pos > 2);  // Skip root dir.
 
-  *result = false;
-  return ERROR_SUCCESS;
+  return ERROR_NOT_A_REPARSE_POINT;
 }
 
 // We get a |full_path| of the forms accepted by IsReparsePoint(), and the name
@@ -279,34 +275,31 @@
 
 // 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);
+bool ConvertToLongPath(base::string16* path) {
+  if (IsPipe(*path))
     return true;
-  }
 
-  base::string16 path;
-  if (IsDevicePath(short_path, &path))
+  base::string16 temp_path;
+  if (IsDevicePath(*path, &temp_path))
     return false;
 
-  bool is_nt_path = IsNTPath(path, &path);
+  bool is_nt_path = IsNTPath(temp_path, &temp_path);
   bool added_implied_device = false;
-  if (!StartsWithDriveLetter(path) && is_nt_path) {
-    path = base::string16(kNTDotPrefix) + path;
+  if (!StartsWithDriveLetter(temp_path) && is_nt_path) {
+    temp_path = base::string16(kNTDotPrefix) + temp_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(),
+  DWORD return_value = ::GetLongPathName(temp_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);
+    return_value = ::GetLongPathName(temp_path.c_str(), long_path_buf.get(),
+                                     size);
   }
 
   DWORD last_error = ::GetLastError();
@@ -314,31 +307,31 @@
                             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'\\');
+    base::string16::size_type last_slash = temp_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))
+    base::string16 begin = temp_path.substr(0, last_slash);
+    base::string16 end = temp_path.substr(last_slash);
+    if (!ConvertToLongPath(&begin))
       return false;
 
     // Ok, it worked. Let's reset the return value.
-    path = begin + end;
+    temp_path = begin + end;
     return_value = 1;
   } else if (0 != return_value) {
-    path = long_path_buf.get();
+    temp_path = long_path_buf.get();
   }
 
   if (return_value != 0) {
     if (added_implied_device)
-      RemoveImpliedDevice(&path);
+      RemoveImpliedDevice(&temp_path);
 
     if (is_nt_path) {
-      *long_path = kNTPrefix;
-      *long_path += path;
+      *path = kNTPrefix;
+      *path += temp_path;
     } else {
-      *long_path = path;
+      *path = temp_path;
     }
 
     return true;
diff --git a/sandbox/win/src/win_utils.h b/sandbox/win/src/win_utils.h
index 3e4565f..bf3ed84 100644
--- a/sandbox/win/src/win_utils.h
+++ b/sandbox/win/src/win_utils.h
@@ -66,16 +66,15 @@
 
 // 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);
+// false and argument is not modified.
+bool ConvertToLongPath(base::string16* 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.
+// Returns ERROR_SUCCESS if the path contains a reparse point,
+// ERROR_NOT_A_REPARSE_POINT if there's no reparse point in this path, or an
+// 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);
+DWORD IsReparsePoint(const base::string16& full_path);
 
 // Returns true if the handle corresponds to the object pointed by this path.
 bool SameObject(HANDLE handle, const wchar_t* full_path);
diff --git a/sandbox/win/src/win_utils_unittest.cc b/sandbox/win/src/win_utils_unittest.cc
index 4cf59b8..15da51b 100644
--- a/sandbox/win/src/win_utils_unittest.cc
+++ b/sandbox/win/src/win_utils_unittest.cc
@@ -22,17 +22,13 @@
   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);
+  EXPECT_EQ(ERROR_NOT_A_REPARSE_POINT, IsReparsePoint(my_folder));
 
-  // 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));
+  EXPECT_EQ(ERROR_NOT_A_REPARSE_POINT, IsReparsePoint(not_found));
 
   base::string16 new_file = base::string16(my_folder) + L"\\foo";
-  EXPECT_EQ(ERROR_SUCCESS, IsReparsePoint(new_file, &result));
-  EXPECT_FALSE(result);
+  EXPECT_EQ(ERROR_NOT_A_REPARSE_POINT, IsReparsePoint(new_file));
 
   // Replace the directory with a reparse point to %temp%.
   HANDLE dir = ::CreateFile(my_folder, FILE_ALL_ACCESS,
@@ -43,8 +39,7 @@
   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_EQ(ERROR_SUCCESS, IsReparsePoint(new_file));
 
   EXPECT_TRUE(DeleteReparsePoint(dir));
   EXPECT_TRUE(::CloseHandle(dir));
diff --git a/sandbox/win/tests/common/controller.cc b/sandbox/win/tests/common/controller.cc
index bdada4b..8d3e29d 100644
--- a/sandbox/win/tests/common/controller.cc
+++ b/sandbox/win/tests/common/controller.cc
@@ -8,6 +8,7 @@
 
 #include "base/memory/shared_memory.h"
 #include "base/process/process.h"
+#include "base/process/process_handle.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/win/windows_version.h"
@@ -123,6 +124,11 @@
   policy_->SetJobLevel(job_level, 0);
   policy_->SetTokenLevel(startup_token, main_token);
 
+  // Close all ALPC ports.
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+    policy_->AddKernelObjectToClose(L"ALPC Port", NULL);
+  }
+
   is_init_ = true;
 }
 
@@ -299,11 +305,12 @@
   // 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)
+    HANDLE raw_handle = nullptr;
+    base::StringToUint(argv[4], reinterpret_cast<unsigned int*>(&raw_handle));
+    if (raw_handle == nullptr)
       return SBOX_TEST_INVALID_PARAMETER;
+    base::SharedMemoryHandle shared_handle(raw_handle,
+                                           base::GetCurrentProcId());
     base::SharedMemory read_only_view(shared_handle, true);
     if (!read_only_view.Map(0))
       return SBOX_TEST_INVALID_PARAMETER;
diff --git a/sandbox/win/tests/validation_tests/suite.cc b/sandbox/win/tests/validation_tests/suite.cc
index 35fb5dd..df2cb3e 100644
--- a/sandbox/win/tests/validation_tests/suite.cc
+++ b/sandbox/win/tests/validation_tests/suite.cc
@@ -167,7 +167,7 @@
 // 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)
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
     return;
 
   TestRunner runner;
@@ -188,7 +188,7 @@
 // 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)
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
     return;
 
   TestRunner runner;
diff --git a/sandbox/win/tools/finder/finder.cc b/sandbox/win/tools/finder/finder.cc
index 9b82962..7753dd0 100644
--- a/sandbox/win/tools/finder/finder.cc
+++ b/sandbox/win/tools/finder/finder.cc
@@ -10,15 +10,12 @@
   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,
@@ -35,14 +32,14 @@
   access_type_ = access_type;
   file_output_ = file_output;
 
-  err_code = sandbox::CreateRestrictedToken(&token_handle_, token_type,
+  err_code = sandbox::CreateRestrictedToken(token_type,
                                             sandbox::INTEGRITY_LEVEL_LAST,
-                                            sandbox::PRIMARY);
+                                            sandbox::PRIMARY, &token_handle_);
   return err_code;
 }
 
 DWORD Finder::Scan() {
-  if (!token_handle_) {
+  if (!token_handle_.IsValid()) {
     return ERROR_NO_TOKEN;
   }
 
diff --git a/sandbox/win/tools/finder/finder.h b/sandbox/win/tools/finder/finder.h
index 23255ce..503447d 100644
--- a/sandbox/win/tools/finder/finder.h
+++ b/sandbox/win/tools/finder/finder.h
@@ -2,9 +2,10 @@
 // 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__
+#ifndef SANDBOX_TOOLS_FINDER_FINDER_H_
+#define SANDBOX_TOOLS_FINDER_FINDER_H_
 
+#include "base/win/scoped_handle.h"
 #include "sandbox/win/src/restricted_token_utils.h"
 #include "sandbox/win/tools/finder/ntundoc.h"
 
@@ -132,7 +133,7 @@
   // Output file for the results.
   FILE * file_output_;
   // Handle to the restricted token.
-  HANDLE token_handle_;
+  base::win::ScopedHandle token_handle_;
   // Stats containing the number of operations performed on the different
   // objects.
   int filesystem_stats_[SIZE_STATS];
@@ -140,4 +141,4 @@
   int kernel_object_stats_[SIZE_STATS];
 };
 
-#endif  // SANDBOX_TOOLS_FINDER_FINDER_H__
+#endif  // SANDBOX_TOOLS_FINDER_FINDER_H_
diff --git a/sandbox/win/tools/launcher/launcher.cc b/sandbox/win/tools/launcher/launcher.cc
index efcc4a4..a037702 100644
--- a/sandbox/win/tools/launcher/launcher.cc
+++ b/sandbox/win/tools/launcher/launcher.cc
@@ -2,6 +2,9 @@
 // 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 "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
 #include "sandbox/win/src/restricted_token_utils.h"
 
 // launcher.exe is an application used to launch another application with a
@@ -11,6 +14,119 @@
 // execute.
 // See the usage (launcher.exe without parameters) for the correct format.
 
+namespace {
+
+// 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. 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,
+                                  base::win::ScopedHandle* job_handle) {
+  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
+  base::win::ScopedHandle primary_token;
+  err_code = sandbox::CreateRestrictedToken(primary_level, INTEGRITY_LEVEL_LAST,
+                                            PRIMARY, &primary_token);
+  if (ERROR_SUCCESS != err_code)
+    return err_code;
+
+
+  // Create the impersonation token (restricted) to be able to start the
+  // process.
+  base::win::ScopedHandle impersonation_token;
+  err_code = sandbox::CreateRestrictedToken(impersonation_level,
+                                            INTEGRITY_LEVEL_LAST,
+                                            IMPERSONATION,
+                                            &impersonation_token);
+  if (ERROR_SUCCESS != err_code)
+    return err_code;
+
+  // 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())) {
+      auto last_error = ::GetLastError();
+      ::TerminateProcess(process_info.process_handle(),
+                         0);  // exit code
+      return last_error;
+    }
+  }
+
+  err_code = job.AssignProcessToJob(process_info.process_handle());
+  if (ERROR_SUCCESS != err_code) {
+    auto last_error = ::GetLastError();
+    ::TerminateProcess(process_info.process_handle(),
+                       0);  // exit code
+    return last_error;
+  }
+
+  // Start the application
+  ::ResumeThread(process_info.thread_handle());
+
+  *job_handle = job.Take();
+
+  return ERROR_SUCCESS;
+}
+
+}  // namespace
+
 #define PARAM_IS(y) (argc > i) && (_wcsicmp(argv[i], y) == 0)
 
 void PrintUsage(const wchar_t *application_name) {
@@ -133,8 +249,8 @@
 
   wprintf(L"\nLaunching command line: \"%ls\"\n", command_line.GetBuffer());
 
-  HANDLE job_handle;
-  DWORD err_code = sandbox::StartRestrictedProcessInJob(
+  base::win::ScopedHandle job_handle;
+  DWORD err_code = StartRestrictedProcessInJob(
       command_line.GetBuffer(),
       primary_level,
       impersonation_level,
@@ -150,7 +266,5 @@
     Sleep(100);
   }
 
-  ::CloseHandle(job_handle);
-
   return 0;
 }
diff --git a/testing/test.gni b/testing/test.gni
index b4cdbed..a150c24 100644
--- a/testing/test.gni
+++ b/testing/test.gni
@@ -24,217 +24,177 @@
       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
-      }
+      # Don't use "*" to forward all variables since some (like output_name
+      # and isolate_file) apply only to the APK below.
       deps = []
-      if (!defined(invoker.use_launcher) || invoker.use_launcher) {
+      forward_variables_from(invoker,
+                             [
+                               "all_dependent_configs",
+                               "allow_circular_includes_from",
+                               "cflags",
+                               "cflags_c",
+                               "cflags_cc",
+                               "check_includes",
+                               "data",
+                               "data_deps",
+                               "datadeps",
+                               "defines",
+                               "deps",
+                               "include_dirs",
+                               "ldflags",
+                               "lib_dirs",
+                               "libs",
+                               "output_extension",
+                               "output_name",
+                               "public",
+                               "public_configs",
+                               "public_deps",
+                               "sources",
+                               "visibility",
+                             ])
+
+      if (!defined(invoker.use_default_launcher) ||
+          invoker.use_default_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) {
+      forward_variables_from(invoker,
+                             [
+                               "android_manifest",
+                               "deps",
+                               "use_default_launcher",
+                               "write_asset_list",
+                             ])
       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
-      }
+      deps += [ ":$library_name" ]
       if (defined(invoker.apk_asset_location)) {
         asset_location = invoker.apk_asset_location
       }
     }
 
+    _test_name = main_target_name
+    if (defined(invoker.output_name)) {
+      _test_name = invoker.output_name
+    }
+    test_runner_script_name = "${_test_name}__test_runner_script"
+    test_runner_script(test_runner_script_name) {
+      test_name = _test_name
+      test_type = "gtest"
+      test_suite = _test_name
+      if (defined(invoker.isolate_file)) {
+        isolate_file = invoker.isolate_file
+      }
+    }
+    incremental_test_runner_script_name =
+        "${_test_name}_incremental__test_runner_script"
+    test_runner_script(incremental_test_runner_script_name) {
+      test_name = "${_test_name}_incremental"
+      test_type = "gtest"
+      test_suite = _test_name
+      incremental_install = true
+      if (defined(invoker.isolate_file)) {
+        isolate_file = invoker.isolate_file
+      }
+    }
+
     group(target_name) {
       testonly = true
-
+      datadeps = [
+        ":$test_runner_script_name",
+      ]
       deps = [
-        ":$library_name",
         ":$apk_name",
       ]
     }
-  } else {
-    executable(target_name) {
-      # See above.
-      configs = []  # Prevent list overwriting warning.
-      configs = invoker.configs
+    group("${target_name}_incremental") {
+      testonly = true
+      datadeps = [
+        ":$incremental_test_runner_script_name",
+      ]
+      deps = [
+        ":${apk_name}_incremental",
+      ]
+    }
+  } else if (is_ios) {
+    if (is_ios) {
+      import("//build/config/ios/rules.gni")
+    }
+
+    ios_app(target_name) {
+      # TODO(GYP): Make this configurable and only provide a default
+      # that can be overridden.
+      info_plist = "//testing/gtest_ios/unittest-Info.plist"
+      app_name = target_name
+      entitlements_path = "//testing/gtest_ios"
+      code_signing_identity = ""
+      testonly = true
 
       # See above call.
       set_sources_assignment_filter([])
 
+      forward_variables_from(invoker,
+                             [
+                               "all_dependent_configs",
+                               "allow_circular_includes_from",
+                               "cflags",
+                               "cflags_c",
+                               "cflags_cc",
+                               "cflags_objc",
+                               "cflags_objcc",
+                               "check_includes",
+                               "configs",
+                               "data",
+                               "data_deps",
+                               "defines",
+                               "include_dirs",
+                               "ldflags",
+                               "libs",
+                               "output_extension",
+                               "output_name",
+                               "public",
+                               "public_configs",
+                               "public_deps",
+                               "sources",
+                               "visibility",
+                             ])
+
+      if (defined(invoker.deps)) {
+        deps = invoker.deps
+      } else {
+        deps = []
+      }
+      deps += [
+        # All shared libraries must have the sanitizer deps to properly link in
+        # asan mode (this target will be empty in other cases).
+        "//build/config/sanitizers:deps",
+      ]
+    }
+  } else {
+    executable(target_name) {
+      forward_variables_from(invoker, "*")
+
       testonly = true
 
-      if (defined(invoker.all_dependent_configs)) {
-        all_dependent_configs = invoker.all_dependent_configs
+      if (!defined(invoker.deps)) {
+        deps = []
       }
-      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 += [
+        # All shared libraries must have the sanitizer deps to properly link in
+        # asan mode (this target will be empty in other cases).
+        "//build/config/sanitizers:deps",
 
-      # 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
-      }
+        # Give tests the default manifest on Windows (a no-op elsewhere).
+        "//build/win:default_exe_manifest",
+      ]
     }
   }
 }
diff --git a/third_party/libevent/BUILD.gn b/third_party/libevent/BUILD.gn
index a1bd0c5..61be1d7 100644
--- a/third_party/libevent/BUILD.gn
+++ b/third_party/libevent/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/nacl/config.gni")
+
 source_set("libevent") {
   sources = [
     "buffer.c",
@@ -31,6 +33,22 @@
   } else if (is_android) {
     sources += [ "epoll.c" ]
     include_dirs = [ "android" ]
+  } else if (is_nacl_nonsfi) {
+    sources -= [
+      "evdns.c",
+      "event_tagging.c",
+      "evrpc.c",
+      "http.c",
+      "select.c",
+      "signal.c",
+    ]
+    sources += [
+      "nacl_nonsfi/config.h",
+      "nacl_nonsfi/event-config.h",
+      "nacl_nonsfi/random.c",
+      "nacl_nonsfi/signal_stub.c",
+    ]
+    include_dirs = [ "nacl_nonsfi" ]
   }
 
   configs -= [ "//build/config/compiler:chromium_code" ]
diff --git a/third_party/libevent/ChangeLog b/third_party/libevent/ChangeLog
index 50eb6b3..893b087 100644
--- a/third_party/libevent/ChangeLog
+++ b/third_party/libevent/ChangeLog
@@ -1,3 +1,55 @@
+Changes in 1.4.15-stable (5 January 2015)
+
+ o Avoid integer overflow bugs in evbuffer_add() and related functions.  See CVE-2014-6272 advisory for more information. (d49bc0e88b81a5812116074dc007f1db0ca1eecd)
+
+ o Pass flags to fcntl(F_SETFL) as int, not long (b3d0382)
+ o Backport and tweak the LICENSE file for 1.4 (8a5ebd3)
+ o set close-on-exec bit for filedescriptors created by dns subsystem (9985231 Ralf Schmitt)
+ o Replace unused case of FD_CLOSEONEXEC with a proper null statement. (44f04a2)
+ o Fix kqueue correctness test on x84_64 (1c25b07)
+ o Avoid deadlock when activating signals. (e0e6958)
+ o Backport doc fix for evhttp_bind_socket. (95b71d0 Marco)
+ o Fix an issue with forking and signal socketpairs in select/poll backends (f0ff765)
+ o Fix compilation on Visual Studio 2010 (53c47c2 VDm)
+ o Defensive programming to prevent (hopefully impossible) stack-stomping (2d8cf0b)
+ o Check for POLLERR, POLLHUP and POLLNVAL for Solaris event ports (353b4ac Trond Norbye)
+ o Fix a bug that could allow dns requests with duplicate tx ids (e50ba5b)
+ o Avoid truncating huge values for content-length (1d6e30e)
+ o Take generated files out of git; add correct m4 magic for libtool to auto* files (7cf794b)
+ o Prefer autoregen -ivf to manual autogen.sh (823d9be)
+
+
+Changes in 1.4.14b-stable
+ o Set the VERSION_INFO correctly for 1.4.14
+
+
+Changes in 1.4.14-stable
+ o Add a .gitignore file for the 1.4 branch. (d014edb)
+ o Backport evbuffer_readln(). (b04cc60 Nicholas Marriott)
+ o Make the evbuffer_readln backport follow the current API (c545485)
+ o Valgrind fix: Clear struct kevent before checking for OSX bug. (5713d5d William Ahern)
+ o Fix a crash when reading badly formatted resolve.conf (5b10d00 Yasuoka Masahiko)
+ o Fix memory-leak of signal handler array with kqueue. [backport] (01f3775)
+ o Update sample/signal-test.c to use newer APIs and not leak. (891765c Evan Jones)
+ o Correct all versions in 1.4 branch (ac0d213)
+ o Make evutil_make_socket_nonblocking() leave any other flags alone. (81c26ba Jardel Weyrich)
+ o Adjusted fcntl() retval comparison on evutil_make_socket_nonblocking(). (5f2e250 Jardel Weyrich)
+ o Correct a debug message in evhttp_parse_request_line (35df59e)
+ o Merge branch 'readln-backport' into patches-1.4 (8771d5b)
+ o Do not send an HTTP error when we've already closed or responded. (4fd2dd9 Pavel Plesov)
+ o Re-add event_siglcb; some old code _was_ still using it. :( (bd03d06)
+ o Make Libevent 1.4 build on win32 with Unicode enabled. (bce58d6 Brodie Thiesfield)
+ o Distribute nmake makefile for 1.4 (20d706d)
+ o do not fail while sending on http connections the client closed. (5c8b446)
+ o make evhttp_send() safe against terminated connections, too (01ea0c5)
+ o Fix a free(NULL) in min_heap.h (2458934)
+ o Fix memory leak when setting up priorities; reported by Alexander Drozdov (cb1a722)
+ o Clean up properly when adding a signal handler fails. (ae6ece0 Gilad Benjamini)
+ o Do not abort HTTP requests missing a reason string. (29d7b32 Pierre Phaneuf)
+ o Fix compile warning in http.c (906d573)
+ o Define _REENTRANT as needed on Solaris, elsewhere (6cbea13)
+
+
 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.
diff --git a/third_party/libevent/Doxyfile b/third_party/libevent/Doxyfile
new file mode 100644
index 0000000..77f6de8
--- /dev/null
+++ b/third_party/libevent/Doxyfile
@@ -0,0 +1,230 @@
+# Doxyfile 1.5.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = libevent
+
+# Place all output under 'doxygen/'
+
+OUTPUT_DIRECTORY        = doxygen/
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = event.h evdns.h evhttp.h evrpc.h
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = YES
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = TAILQ_ENTRY RB_ENTRY _EVENT_DEFINED_TQENTRY
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
diff --git a/third_party/libevent/LICENSE b/third_party/libevent/LICENSE
index af977a4..cabd9fc 100644
--- a/third_party/libevent/LICENSE
+++ b/third_party/libevent/LICENSE
@@ -1,5 +1,9 @@
-Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
-Copyright 2007-2009 Niels Provos and Nick Mathewson
+Libevent is available for use under the following license, commonly known
+as the 3-clause (or "modified") BSD license:
+
+==============================
+Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+Copyright (c) 2007-2010 Niels Provos and Nick Mathewson
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
@@ -22,3 +26,28 @@
 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.
+==============================
+
+Portions of Libevent are based on works by others, also made available by
+them under the three-clause BSD license above.  The copyright notices are
+available in the corresponding source files; the license is as above.  Here's
+a list:
+
+log.c:
+   Copyright (c) 2000 Dug Song <dugsong@monkey.org>
+   Copyright (c) 1993 The Regents of the University of California.
+
+strlcpy.c:
+   Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+
+win32.c:
+   Copyright (c) 2003 Michael A. Davis <mike@datanerds.net>
+
+evport.c:
+   Copyright (c) 2007 Sun Microsystems
+
+min_heap.h:
+   Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
+
+tree.h:
+   Copyright 2002 Niels Provos <provos@citi.umich.edu>
diff --git a/third_party/libevent/Makefile.am b/third_party/libevent/Makefile.am
index dc78ef1..c1ed62a 100644
--- a/third_party/libevent/Makefile.am
+++ b/third_party/libevent/Makefile.am
@@ -1,5 +1,7 @@
 AUTOMAKE_OPTIONS = foreign no-dependencies
 
+ACLOCAL_AMFLAGS = -I m4
+
 # This is the point release for libevent.  It shouldn't include any
 # a/b/c/d/e notations.
 RELEASE = 1.4
@@ -24,12 +26,36 @@
 # compatibility with old binaries.  Increment Current.  Set Age to 0,
 # since we're backward compatible with no previous APIs.  Set Revision
 # to 0 too.
+VERSION_INFO = 4:1:2
 
+###
 # 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
+#   We started using Libtool around version 1.0d.  For all versions from
+#   1.0d through 1.3e, we set RELEASE to the version name, and
+#   VERSION_INFO to something haphazard.  The didn't matter, since
+#   setting RELEASE meant that no version of Libevent was treated as
+#   binary-compatible with any other version.
+#
+#   As of 1.4.0-beta, we set RELEASE to "1.4", so that releases in the
+#   1.4.x series could be potentially binary-compatible with one another,
+#   but not with any other series.  (They aren't.)  We didn't necessarily
+#   set VERSION_INFO correctly, or update it as often as we should have.
+#   The VERSION_INFO values were:
+#    1.4.0-beta .. 1.4.4-stable     : 2:0:0   [See note 1]
+#    1.4.5-stable                   : 3:0:1   (compatible ABI change)
+#    1.4.6-stable                   : 3:1:1   (no ABI change)
+#    1.4.7-stable                   : 3:1:1   [see note 1]
+#    1.4.8-stable                   : 3:2:1   (no ABI change)
+#    1.4.9-stable                   : 3:2:1   [see note 1]
+#    1.4.10-stable                  : 3:3:1   (no ABI change)
+#    1.4.11-stable .. 1.4.13-stable : 3:3:1   [see note 1]
+#    1.4.14a-stable:                : 3:3:2   [see note 2]
+#    1.4.14b-stable:                : 4:0:2   (compatible ABI change)
+#    1.4.15-stable:                 : 4:1:2   (no ABI change)
+#
+# [1]: Using the same VERSION_INFO value was wrong; we should have been
+#      updating the Revision field.
+# [2]: We set the VERSION_INFO completely wrong on 1.4.14b-stable
 
 bin_SCRIPTS = event_rpcgen.py
 
@@ -53,7 +79,9 @@
 	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
+	WIN32-Prj/libevent.sln WIN32-Prj/libevent.vcproj \
+	Makefile.nmake test/Makefile.nmake \
+	LICENSE
 
 lib_LTLIBRARIES = libevent.la libevent_core.la libevent_extra.la
 
diff --git a/third_party/libevent/Makefile.in b/third_party/libevent/Makefile.in
deleted file mode 100644
index 4d96c74..0000000
--- a/third_party/libevent/Makefile.in
+++ /dev/null
@@ -1,976 +0,0 @@
-# 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/Makefile.nmake b/third_party/libevent/Makefile.nmake
new file mode 100644
index 0000000..f8d5722
--- /dev/null
+++ b/third_party/libevent/Makefile.nmake
@@ -0,0 +1,48 @@
+# WATCH OUT!  This makefile is a work in progress.  It is probably missing
+# tons of important things.  DO NOT RELY ON IT TO BUILD A GOOD LIBEVENT.
+
+# Needed for correctness
+CFLAGS=/Iinclude /Icompat /IWIN32-Code /DWIN32 /DHAVE_CONFIG_H /I.
+
+# For optimization and warnings
+CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
+
+# XXXX have a debug mode
+
+LIBFLAGS=/nologo
+
+
+CORE_OBJS=event.obj buffer.obj evbuffer.obj \
+	log.obj evutil.obj \
+	strlcpy.obj signal.obj win32.obj
+EXTRA_OBJS=event_tagging.obj http.obj evdns.obj evrpc.obj
+
+ALL_OBJS=$(CORE_OBJS) $(WIN_OBJS) $(EXTRA_OBJS)
+STATIC_LIBS=libevent_core.lib libevent_extras.lib libevent.lib
+
+
+all: static_libs tests
+
+static_libs: $(STATIC_LIBS)
+
+win32.obj: WIN32-Code\win32.c
+	$(CC) $(CFLAGS) /c WIN32-Code\win32.c
+
+libevent_core.lib: $(CORE_OBJS)
+	lib $(LIBFLAGS) $(CORE_OBJS) /out:libevent_core.lib 
+
+libevent_extras.lib: $(EXTRA_OBJS)
+	lib $(LIBFLAGS) $(EXTRA_OBJS) /out:libevent_extras.lib
+
+libevent.lib: $(CORE_OBJ) $(EXTRA_OBJS)
+	lib $(LIBFLAGS) $(CORE_OBJS) $(EXTRA_OBJS) /out:libevent.lib
+
+clean:
+	del $(ALL_OBJS)
+	del $(STATIC_LIBS)
+	cd test
+	$(MAKE) /F Makefile.nmake clean
+
+tests:
+	cd test
+	$(MAKE) /F Makefile.nmake
diff --git a/third_party/libevent/README.chromium b/third_party/libevent/README.chromium
index 939a353..3d626c5 100644
--- a/third_party/libevent/README.chromium
+++ b/third_party/libevent/README.chromium
@@ -1,6 +1,6 @@
 Name: libevent
-URL: http://www.monkey.org/~provos/libevent/
-Version: 1.4.13
+URL: http://libevent.org/
+Version: 1.4.15
 License: BSD
 Security Critical: yes
 
@@ -12,17 +12,23 @@
    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.
+3) chromium.patch is applied to make the following changes:
+   - Allow libevent to be used without being installed by changing <...>
+     #includes to "...".
+   - Fix a race condition in event_del.
+   - Optimistically assume CLOCK_MONOTONIC is available and fallback if it
+     fails, rather than explicitly testing for it.
+   - Remove an unneeded variable that causes a -Werror build failure.
+   - Revert the patch from http://sourceforge.net/p/levent/bugs/223/ that
+     introduces use-after-free memory corruption when an event callback frees
+     the struct event memory.
 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
+5) 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
+6) 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
+7) 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
deleted file mode 100644
index 4af9376..0000000
--- a/third_party/libevent/aclocal.m4
+++ /dev/null
@@ -1,7498 +0,0 @@
-# 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/event-config.h b/third_party/libevent/android/event-config.h
index 7745519..6563cb7 100644
--- a/third_party/libevent/android/event-config.h
+++ b/third_party/libevent/android/event-config.h
@@ -209,6 +209,13 @@
 /* Define if kqueue works correctly with pipes */
 /* #undef _EVENT_HAVE_WORKING_KQUEUE */
 
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
 /* Name of package */
 #define _EVENT_PACKAGE "libevent"
 
@@ -224,6 +231,9 @@
 /* Define to the one symbol short name of this package. */
 #define _EVENT_PACKAGE_TARNAME ""
 
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
 /* Define to the version of this package. */
 #define _EVENT_PACKAGE_VERSION ""
 
@@ -246,7 +256,7 @@
 #define _EVENT_TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define _EVENT_VERSION "1.4.13-stable"
+#define _EVENT_VERSION "1.4.15"
 
 /* Define to appropriate substitue if compiler doesnt have __func__ */
 /* #undef _EVENT___func__ */
diff --git a/third_party/libevent/autogen.sh b/third_party/libevent/autogen.sh
old mode 100644
new mode 100755
index 6d4275a..099cb30
--- a/third_party/libevent/autogen.sh
+++ b/third_party/libevent/autogen.sh
@@ -1,4 +1,8 @@
 #!/bin/sh
+if [ -x "`which autoreconf 2>/dev/null`" ] ; then
+   exec autoreconf -ivf
+fi
+
 LIBTOOLIZE=libtoolize
 SYSNAME=`uname`
 if [ "x$SYSNAME" = "xDarwin" ] ; then
diff --git a/third_party/libevent/buffer.c b/third_party/libevent/buffer.c
index dfaca5d..ebf35c9 100644
--- a/third_party/libevent/buffer.c
+++ b/third_party/libevent/buffer.c
@@ -64,6 +64,7 @@
 #include "event.h"
 #include "config.h"
 #include "evutil.h"
+#include "./log.h"
 
 struct evbuffer *
 evbuffer_new(void)
@@ -143,7 +144,8 @@
 	va_list aq;
 
 	/* make sure that at least some space is available */
-	evbuffer_expand(buf, 64);
+	if (evbuffer_expand(buf, 64) < 0)
+		return (-1);
 	for (;;) {
 		size_t used = buf->misalign + buf->off;
 		buffer = (char *)buf->buffer + buf->off;
@@ -248,6 +250,92 @@
 	return (line);
 }
 
+
+char *
+evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
+		enum evbuffer_eol_style eol_style)
+{
+	u_char *data = EVBUFFER_DATA(buffer);
+	u_char *start_of_eol, *end_of_eol;
+	size_t len = EVBUFFER_LENGTH(buffer);
+	char *line;
+	unsigned int i, n_to_copy, n_to_drain;
+
+	if (n_read_out)
+		*n_read_out = 0;
+
+	/* depending on eol_style, set start_of_eol to the first character
+	 * in the newline, and end_of_eol to one after the last character. */
+	switch (eol_style) {
+	case EVBUFFER_EOL_ANY:
+		for (i = 0; i < len; i++) {
+			if (data[i] == '\r' || data[i] == '\n')
+				break;
+		}
+		if (i == len)
+			return (NULL);
+		start_of_eol = data+i;
+		++i;
+		for ( ; i < len; i++) {
+			if (data[i] != '\r' && data[i] != '\n')
+				break;
+		}
+		end_of_eol = data+i;
+		break;
+	case EVBUFFER_EOL_CRLF:
+		end_of_eol = memchr(data, '\n', len);
+		if (!end_of_eol)
+			return (NULL);
+		if (end_of_eol > data && *(end_of_eol-1) == '\r')
+			start_of_eol = end_of_eol - 1;
+		else
+			start_of_eol = end_of_eol;
+		end_of_eol++; /*point to one after the LF. */
+		break;
+	case EVBUFFER_EOL_CRLF_STRICT: {
+		u_char *cp = data;
+		while ((cp = memchr(cp, '\r', len-(cp-data)))) {
+			if (cp < data+len-1 && *(cp+1) == '\n')
+				break;
+			if (++cp >= data+len) {
+				cp = NULL;
+				break;
+			}
+		}
+		if (!cp)
+			return (NULL);
+		start_of_eol = cp;
+		end_of_eol = cp+2;
+		break;
+	}
+	case EVBUFFER_EOL_LF:
+		start_of_eol = memchr(data, '\n', len);
+		if (!start_of_eol)
+			return (NULL);
+		end_of_eol = start_of_eol + 1;
+		break;
+	default:
+		return (NULL);
+	}
+
+	n_to_copy = start_of_eol - data;
+	n_to_drain = end_of_eol - data;
+
+	if ((line = malloc(n_to_copy+1)) == NULL) {
+		event_warn("%s: out of memory\n", __func__);
+		return (NULL);
+	}
+
+	memcpy(line, data, n_to_copy);
+	line[n_to_copy] = '\0';
+
+	evbuffer_drain(buffer, n_to_drain);
+	if (n_read_out)
+		*n_read_out = (size_t)n_to_copy;
+
+	return (line);
+}
+
 /* Adds data to an event buffer */
 
 static void
@@ -258,31 +346,47 @@
 	buf->misalign = 0;
 }
 
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t)-1)
+#endif
+
 /* 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;
+	size_t used = buf->misalign + buf->off;
+
+	assert(buf->totallen >= used);
 
 	/* If we can fit all the data, then we don't have to do anything */
-	if (buf->totallen >= need)
+	if (buf->totallen - used >= datlen)
 		return (0);
+	/* If we would need to overflow to fit this much data, we can't
+	 * do anything. */
+	if (datlen > SIZE_MAX - buf->off)
+		return (-1);
 
 	/*
 	 * If the misalignment fulfills our data needs, we just force an
 	 * alignment to happen.  Afterwards, we have enough space.
 	 */
-	if (buf->misalign >= datlen) {
+	if (buf->totallen - buf->off >= datlen) {
 		evbuffer_align(buf);
 	} else {
 		void *newbuf;
 		size_t length = buf->totallen;
+		size_t need = buf->off + datlen;
 
 		if (length < 256)
 			length = 256;
-		while (length < need)
-			length <<= 1;
+		if (need < SIZE_MAX / 2) {
+			while (length < need) {
+				length <<= 1;
+			}
+		} else {
+			length = need;
+		}
 
 		if (buf->orig_buffer != buf->buffer)
 			evbuffer_align(buf);
@@ -299,10 +403,10 @@
 int
 evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
 {
-	size_t need = buf->misalign + buf->off + datlen;
+	size_t used = buf->misalign + buf->off;
 	size_t oldoff = buf->off;
 
-	if (buf->totallen < need) {
+	if (buf->totallen - used < datlen) {
 		if (evbuffer_expand(buf, datlen) == -1)
 			return (-1);
 	}
diff --git a/third_party/libevent/chromium.patch b/third_party/libevent/chromium.patch
index 08e0122..5771a17 100644
--- a/third_party/libevent/chromium.patch
+++ b/third_party/libevent/chromium.patch
@@ -1,5 +1,17 @@
+diff --git a/third_party/libevent/buffer.c b/third_party/libevent/buffer.c
+index 64324bb..ebf35c9 100644
+--- a/third_party/libevent/buffer.c
++++ b/third_party/libevent/buffer.c
+@@ -356,7 +356,6 @@ int
+ evbuffer_expand(struct evbuffer *buf, size_t datlen)
+ {
+ 	size_t used = buf->misalign + buf->off;
+-	size_t need;
+ 
+ 	assert(buf->totallen >= used);
+ 
 diff --git a/third_party/libevent/evdns.c b/third_party/libevent/evdns.c
-index f07ecc9..da6ea19 100644
+index fa23163..f1c70d0 100644
 --- a/third_party/libevent/evdns.c
 +++ b/third_party/libevent/evdns.c
 @@ -134,7 +134,7 @@
@@ -8,7 +20,7 @@
  #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
@@ -17,74 +29,15 @@
 +++ 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
+index da6cd42..36b1c51 100644
 --- a/third_party/libevent/event.c
 +++ b/third_party/libevent/event.c
 @@ -107,7 +107,7 @@ static const struct eventop *eventops[] = {
@@ -94,9 +47,9 @@
 -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 **);
+ /* Handle signals - This is a deprecated interface */
+ int (*event_sigcb)(void);		/* Signal callback when gotsig is set */
+@@ -124,17 +124,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 *);
  
@@ -114,7 +67,7 @@
  static int
  gettime(struct event_base *base, struct timeval *tp)
  {
-@@ -140,18 +129,18 @@ gettime(struct event_base *base, struct timeval *tp)
+@@ -144,18 +133,18 @@ gettime(struct event_base *base, struct timeval *tp)
  	}
  
  #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
@@ -138,11 +91,100 @@
  	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__);
+@@ -182,7 +171,6 @@ event_base_new(void)
+ 	event_sigcb = NULL;
+ 	event_gotsig = 0;
  
 -	detect_monotonic();
  	gettime(base, &base->event_tv);
  	
  	min_heap_ctor(&base->timeheap);
+@@ -398,12 +386,9 @@ event_process_active(struct event_base *base)
+ 			ncalls--;
+ 			ev->ev_ncalls = ncalls;
+ 			(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
+-			if (event_gotsig || base->event_break) {
+-			  	ev->ev_pncalls = NULL;
++			if (event_gotsig || base->event_break)
+ 				return;
+-			}
+ 		}
+-		ev->ev_pncalls = NULL;
+ 	}
+ }
+ 
+@@ -808,8 +793,6 @@ int
+ event_del(struct event *ev)
+ {
+ 	struct event_base *base;
+-	const struct eventop *evsel;
+-	void *evbase;
+ 
+ 	event_debug(("event_del: %p, callback %p",
+ 		 ev, ev->ev_callback));
+@@ -819,8 +802,6 @@ event_del(struct event *ev)
+ 		return (-1);
+ 
+ 	base = ev->ev_base;
+-	evsel = base->evsel;
+-	evbase = base->evbase;
+ 
+ 	assert(!(ev->ev_flags & ~EVLIST_ALL));
+ 
+@@ -838,7 +819,7 @@ event_del(struct event *ev)
+ 
+ 	if (ev->ev_flags & EVLIST_INSERTED) {
+ 		event_queue_remove(base, ev, EVLIST_INSERTED);
+-		return (evsel->del(evbase, ev));
++		return (base->evsel->del(base->evbase, ev));
+ 	}
+ 
+ 	return (0);
+diff --git a/third_party/libevent/event.h b/third_party/libevent/event.h
+index d1f5d9e..f0887b9 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/evhttp.h b/third_party/libevent/evhttp.h
+index cba8be1..48c1d91 100644
+--- a/third_party/libevent/evhttp.h
++++ b/third_party/libevent/evhttp.h
+@@ -27,7 +27,7 @@
+ #ifndef _EVHTTP_H_
+ #define _EVHTTP_H_
+ 
+-#include <event.h>
++#include "event.h"
+ 
+ #ifdef __cplusplus
+ extern "C" {
+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/compat/sys/_time.h b/third_party/libevent/compat/sys/_time.h
deleted file mode 100644
index 8cabb0d..0000000
--- a/third_party/libevent/compat/sys/_time.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*	$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/config.guess b/third_party/libevent/config.guess
deleted file mode 100644
index f32079a..0000000
--- a/third_party/libevent/config.guess
+++ /dev/null
@@ -1,1526 +0,0 @@
-#! /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
deleted file mode 100644
index 149942c..0000000
--- a/third_party/libevent/config.h.in
+++ /dev/null
@@ -1,265 +0,0 @@
-/* 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
deleted file mode 100644
index 6759825..0000000
--- a/third_party/libevent/config.sub
+++ /dev/null
@@ -1,1658 +0,0 @@
-#! /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
deleted file mode 100755
index c98d1ff..0000000
--- a/third_party/libevent/configure
+++ /dev/null
Binary files differ
diff --git a/third_party/libevent/configure.in b/third_party/libevent/configure.in
index bf21399..468d774 100644
--- a/third_party/libevent/configure.in
+++ b/third_party/libevent/configure.in
@@ -2,10 +2,16 @@
 dnl Dug Song <dugsong@monkey.org>
 AC_INIT(event.c)
 
-AM_INIT_AUTOMAKE(libevent,1.4.13-stable)
+AM_INIT_AUTOMAKE(libevent,1.4.15)
 AM_CONFIG_HEADER(config.h)
 dnl AM_MAINTAINER_MODE
 
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_CANONICAL_HOST
+
+AC_DEFINE(NUMERIC_VERSION, 0x01040f00, [Numeric representation of the version])
+
 dnl Initialize prefix.
 if test "$prefix" = "NONE"; then
    prefix="/usr/local"
@@ -24,6 +30,25 @@
         CFLAGS="$CFLAGS -fno-strict-aliasing"
 fi
 
+dnl Libevent 1.4 isn't multithreaded, but some of its functions are
+dnl documented to be reentrant.  If you don't define the right macros
+dnl on some platforms, you get non-reentrant versions of the libc
+dnl functinos (like an errno that's shared by all threads).
+AC_MSG_CHECKING([whether we need extra flags to make libc reentrant])
+case $host in
+   *solaris* | *-osf* | *-hpux* )
+     AC_MSG_RESULT([-D_REENTRANT])
+     CFLAGS="$CFLAGS -D_REENTRANT"
+     ;;
+   *-aix* | *-freebsd* | *-darwin* )
+     AC_MSG_RESULT([-D_THREAD_SAFE])
+     CFLAGS="$CFLAGS -D_THREAD_SAFE"
+     ;;
+   *)
+     AC_MSG_RESULT(no)
+     ;;
+esac
+
 AC_ARG_ENABLE(gcc-warnings,
      AS_HELP_STRING(--enable-gcc-warnings, enable verbose warnings with GCC))
 
@@ -223,13 +248,14 @@
         if ((kq = kqueue()) == -1)
 		exit(1);
 
+	memset(&ev, 0, sizeof(ev));
 	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;
diff --git a/third_party/libevent/evdns.c b/third_party/libevent/evdns.c
index 6fa971c..4486fb8 100644
--- a/third_party/libevent/evdns.c
+++ b/third_party/libevent/evdns.c
@@ -55,9 +55,7 @@
 #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
@@ -160,6 +158,15 @@
 
 #define CLASS_INET     EVDNS_CLASS_INET
 
+#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) (void)0
+#endif
+
 struct request {
 	u8 *request;  /* the dns packet data */
 	unsigned int request_len;
@@ -1101,20 +1108,12 @@
 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;
+
+		if (request_find_from_trans_id(trans_id) == NULL)
+			return trans_id;
 	}
 }
 
@@ -2134,7 +2133,8 @@
 
 	ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
 	if (ns->socket < 0) { err = 1; goto out1; }
-        evutil_make_socket_nonblocking(ns->socket);
+	FD_CLOSEONEXEC(ns->socket);
+	evutil_make_socket_nonblocking(ns->socket);
 
 	ns->address = address;
 	ns->port = htons(port);
@@ -2706,7 +2706,7 @@
 		const char *const nameserver = NEXT_TOKEN;
 		struct in_addr ina;
 
-		if (inet_aton(nameserver, &ina)) {
+		if (nameserver && inet_aton(nameserver, &ina)) {
 			/* address is valid */
 			evdns_nameserver_add(ina.s_addr);
 		}
@@ -2848,7 +2848,7 @@
 	IP_ADDR_STRING *ns;
 	GetNetworkParams_fn_t fn;
 
-	if (!(handle = LoadLibrary("iphlpapi.dll"))) {
+	if (!(handle = LoadLibraryA("iphlpapi.dll"))) {
 		log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
 		status = -1;
 		goto done;
@@ -2918,13 +2918,13 @@
 	DWORD bufsz = 0, type = 0;
 	int status = 0;
 
-	if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
+	if (RegQueryValueExA(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)
+	if (RegQueryValueExA(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
 	    == ERROR_SUCCESS && bufsz > 1) {
 		status = evdns_nameserver_ip_add_line(buf);
 	}
@@ -2954,12 +2954,12 @@
 	if (((int)GetVersion()) > 0) { /* NT */
 		HKEY nt_key = 0, interfaces_key = 0;
 
-		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
+		if (RegOpenKeyExA(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,
+		r = RegOpenKeyExA(nt_key, "Interfaces", 0,
 			     KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
 			     &interfaces_key);
 		if (r != ERROR_SUCCESS) {
@@ -2974,7 +2974,7 @@
 		RegCloseKey(nt_key);
 	} else {
 		HKEY win_key = 0;
-		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
+		if (RegOpenKeyExA(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;
diff --git a/third_party/libevent/event.c b/third_party/libevent/event.c
index 8b6cae5..36b1c51 100644
--- a/third_party/libevent/event.c
+++ b/third_party/libevent/event.c
@@ -109,6 +109,10 @@
 extern struct event_base *evsignal_base;
 static int use_monotonic = 1;
 
+/* Handle signals - This is a deprecated interface */
+int (*event_sigcb)(void);		/* Signal callback when gotsig is set */
+volatile sig_atomic_t event_gotsig;	/* Set in signal handler */
+
 /* Prototypes */
 static void	event_queue_insert(struct event_base *, struct event *, int);
 static void	event_queue_remove(struct event_base *, struct event *, int);
@@ -164,6 +168,9 @@
 	if ((base = calloc(1, sizeof(struct event_base))) == NULL)
 		event_err(1, "%s: calloc", __func__);
 
+	event_sigcb = NULL;
+	event_gotsig = 0;
+
 	gettime(base, &base->event_tv);
 	
 	min_heap_ctor(&base->timeheap);
@@ -260,9 +267,14 @@
 	int res = 0;
 	struct event *ev;
 
+#if 0
+	/* Right now, reinit always takes effect, since even if the
+	   backend doesn't require it, the signal socketpair code does.
+	 */
 	/* check if this event mechanism requires reinit */
 	if (!evsel->need_reinit)
 		return (0);
+#endif
 
 	/* prevent internal delete */
 	if (base->sig.ev_signal_added) {
@@ -275,7 +287,7 @@
 			    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);
@@ -305,7 +317,10 @@
 	if (base->event_count_active)
 		return (-1);
 
-	if (base->nactivequeues && npriorities != base->nactivequeues) {
+	if (npriorities == base->nactivequeues)
+		return (0);
+
+	if (base->nactivequeues) {
 		for (i = 0; i < base->nactivequeues; ++i) {
 			free(base->activequeues[i]);
 		}
@@ -371,7 +386,7 @@
 			ncalls--;
 			ev->ev_ncalls = ncalls;
 			(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
-			if (base->event_break)
+			if (event_gotsig || base->event_break)
 				return;
 		}
 	}
@@ -476,6 +491,18 @@
 			break;
 		}
 
+		/* You cannot use this interface for multi-threaded apps */
+		while (event_gotsig) {
+			event_gotsig = 0;
+			if (event_sigcb) {
+				res = (*event_sigcb)();
+				if (res == -1) {
+					errno = EINTR;
+					return (-1);
+				}
+			}
+		}
+
 		timeout_correct(base, &tv);
 
 		tv_p = &tv;
diff --git a/third_party/libevent/event.h b/third_party/libevent/event.h
index 72e9b8b..f0887b9 100644
--- a/third_party/libevent/event.h
+++ b/third_party/libevent/event.h
@@ -1030,6 +1030,38 @@
 char *evbuffer_readline(struct evbuffer *);
 
 
+/** Used to tell evbuffer_readln what kind of line-ending to look for.
+ */
+enum evbuffer_eol_style {
+	/** Any sequence of CR and LF characters is acceptable as an EOL. */
+	EVBUFFER_EOL_ANY,
+	/** An EOL is an LF, optionally preceded by a CR.  This style is
+	 * most useful for implementing text-based internet protocols. */
+	EVBUFFER_EOL_CRLF,
+	/** An EOL is a CR followed by an LF. */
+	EVBUFFER_EOL_CRLF_STRICT,
+	/** An EOL is a LF. */
+        EVBUFFER_EOL_LF
+};
+
+/**
+ * Read a single line from an event buffer.
+ *
+ * Reads a line terminated by an EOL as determined by the evbuffer_eol_style
+ * argument.  Returns a newly allocated nul-terminated string; the caller must
+ * free the returned value.  The EOL is not included in the returned string.
+ *
+ * @param buffer the evbuffer to read from
+ * @param n_read_out if non-NULL, points to a size_t that is set to the
+ *       number of characters in the returned string.  This is useful for
+ *       strings that can contain NUL characters.
+ * @param eol_style the style of line-ending to use.
+ * @return pointer to a single line, or NULL if an error occurred
+ */
+char *evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
+    enum evbuffer_eol_style eol_style);
+
+
 /**
   Move data from one evbuffer into another evbuffer.
 
diff --git a/third_party/libevent/evhttp.h b/third_party/libevent/evhttp.h
index 30dee8b..48c1d91 100644
--- a/third_party/libevent/evhttp.h
+++ b/third_party/libevent/evhttp.h
@@ -81,7 +81,7 @@
  * @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
+ * @return 0 on success, -1 on failure
  * @see evhttp_free()
  */
 int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
@@ -221,7 +221,8 @@
 
 	struct evbuffer *input_buffer;	/* read data */
 	ev_int64_t ntoread;
-	int chunked;
+	int chunked:1,                  /* a chunked request */
+	    userdone:1;                 /* the user has sent all data */
 
 	struct evbuffer *output_buffer;	/* outgoing post or data */
 
@@ -252,6 +253,9 @@
 /** Frees the request object and removes associated events. */
 void evhttp_request_free(struct evhttp_request *req);
 
+/** Returns the connection object associated with the request or NULL */
+struct evhttp_connection *evhttp_request_get_connection(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
diff --git a/third_party/libevent/evport.c b/third_party/libevent/evport.c
index a2ee1bc..1f5ebc4 100644
--- a/third_party/libevent/evport.c
+++ b/third_party/libevent/evport.c
@@ -367,6 +367,12 @@
 		if (pevt->portev_events & POLLOUT)
 			res |= EV_WRITE;
 
+		/*
+		 * Check for the error situations or a hangup situation
+		 */
+		if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL))
+			res |= EV_READ|EV_WRITE;
+
 		assert(epdp->ed_nevents > fd);
 		fdi = &(epdp->ed_fds[fd]);
 
diff --git a/third_party/libevent/evutil.c b/third_party/libevent/evutil.c
index 564377d..cc6d0f4 100644
--- a/third_party/libevent/evutil.c
+++ b/third_party/libevent/evutil.c
@@ -168,10 +168,17 @@
 		ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking);
 	}
 #else
-	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
-		event_warn("fcntl(O_NONBLOCK)");
-		return -1;
-}	
+	{
+		int flags;
+		if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
+			event_warn("fcntl(%d, F_GETFL)", fd);
+			return -1;
+		}
+		if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+			event_warn("fcntl(%d, F_SETFL)", fd);
+			return -1;
+		}
+	}
 #endif
 	return 0;
 }
diff --git a/third_party/libevent/freebsd/event-config.h b/third_party/libevent/freebsd/event-config.h
index 662abc8..be1eae4 100644
--- a/third_party/libevent/freebsd/event-config.h
+++ b/third_party/libevent/freebsd/event-config.h
@@ -212,6 +212,13 @@
 /* Define if kqueue works correctly with pipes */
 #define _EVENT_HAVE_WORKING_KQUEUE 1
 
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
 /* Name of package */
 #define _EVENT_PACKAGE "libevent"
 
@@ -227,6 +234,9 @@
 /* Define to the one symbol short name of this package. */
 #define _EVENT_PACKAGE_TARNAME ""
 
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
 /* Define to the version of this package. */
 #define _EVENT_PACKAGE_VERSION ""
 
@@ -249,7 +259,7 @@
 #define _EVENT_TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define _EVENT_VERSION "1.4.13-stable"
+#define _EVENT_VERSION "1.4.15"
 
 /* Define to appropriate substitue if compiler doesnt have __func__ */
 /* #undef _EVENT___func__ */
diff --git a/third_party/libevent/http.c b/third_party/libevent/http.c
index b04ad54..4abce23 100644
--- a/third_party/libevent/http.c
+++ b/third_party/libevent/http.c
@@ -99,8 +99,13 @@
 #define NI_MAXSERV 32
 #define NI_MAXHOST 1025
 
+#ifndef NI_NUMERICHOST
 #define NI_NUMERICHOST 1
+#endif
+
+#ifndef NI_NUMERICSERV
 #define NI_NUMERICSERV 2
+#endif
 
 static int
 fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 
@@ -142,6 +147,8 @@
 #endif
 
 #ifndef HAVE_GETADDRINFO
+/* Apparently msvc2010 does have an addrinfo definition visible here */
+#if !defined(WIN32) || !defined(_MSC_VER) || (_MSC_VER < 1600)
 struct addrinfo {
 	int ai_family;
 	int ai_socktype;
@@ -150,6 +157,7 @@
 	struct sockaddr *ai_addr;
 	struct addrinfo *ai_next;
 };
+#endif
 static int
 fake_getaddrinfo(const char *hostname, struct addrinfo *ai)
 {
@@ -390,7 +398,7 @@
 	/* 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];
+		char size[22];
 		evutil_snprintf(size, sizeof(size), "%ld",
 		    (long)EVBUFFER_LENGTH(req->output_buffer));
 		evhttp_add_header(req->output_headers, "Content-Length", size);
@@ -447,7 +455,7 @@
 {
 	if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
 	    evhttp_find_header(headers,	"Content-Length") == NULL) {
-		char len[12];
+		char len[22];
 		evutil_snprintf(len, sizeof(len), "%ld", content_length);
 		evhttp_add_header(headers, "Content-Length", len);
 	}
@@ -606,8 +614,18 @@
 		 * 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.
+		 * connection open and we timeout on the read.  when
+		 * the request is still being used for sending, we
+		 * need to disassociated it from the connection here.
 		 */
+		if (!req->userdone) {
+			/* remove it so that it will not be freed */
+			TAILQ_REMOVE(&req->evcon->requests, req, next);
+			/* indicate that this request no longer has a
+			 * connection object
+			 */
+			req->evcon = NULL;
+		}
 		return (-1);
 	case EVCON_HTTP_INVALID_HEADER:
 	default:	/* xxx: probably should just error on default */
@@ -654,11 +672,13 @@
 	cb = req->cb;
 	cb_arg = req->cb_arg;
 
+	/* do not fail all requests; the next request is going to get
+	 * send over a new connection.   when a user cancels a request,
+	 * all other pending requests should be processed as normal
+	 */
 	TAILQ_REMOVE(&evcon->requests, req, next);
 	evhttp_request_free(req);
 
-	/* xxx: maybe we should fail all requests??? */
-
 	/* reset the connection */
 	evhttp_connection_reset(evcon);
 	
@@ -751,7 +771,7 @@
 			 */
 			evhttp_connection_start_detectclose(evcon);
 		}
-	} else {
+	} else if (evcon->state != EVCON_DISCONNECTED) {
 		/*
 		 * incoming connection - we need to leave the request on the
 		 * connection so that we can reply to it.
@@ -933,6 +953,7 @@
 		return;
 	} else if (n == 0) {
 		/* Connection closed */
+		evcon->state = EVCON_DISCONNECTED;
 		evhttp_connection_done(evcon);
 		return;
 	}
@@ -990,7 +1011,11 @@
 			(*evcon->closecb)(evcon, evcon->closecb_arg);
 	}
 
-	/* remove all requests that might be queued on this connection */
+	/* remove all requests that might be queued on this
+	 * connection.  for server connections, this should be empty.
+	 * because it gets dequeued either in evhttp_connection_done or
+	 * evhttp_connection_fail.
+	 */
 	while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
 		TAILQ_REMOVE(&evcon->requests, req, next);
 		evhttp_request_free(req);
@@ -1213,15 +1238,14 @@
 {
 	char *protocol;
 	char *number;
-	char *readable;
+	const char *readable = "";
 
 	protocol = strsep(&line, " ");
 	if (line == NULL)
 		return (-1);
 	number = strsep(&line, " ");
-	if (line == NULL)
-		return (-1);
-	readable = line;
+	if (line != NULL)
+		readable = line;
 
 	if (strcmp(protocol, "HTTP/1.0") == 0) {
 		req->major = 1;
@@ -1294,7 +1318,7 @@
 	}
 
 	if ((req->uri = strdup(uri)) == NULL) {
-		event_debug(("%s: evhttp_decode_uri", __func__));
+		event_debug(("%s: strdup", __func__));
 		return (-1);
 	}
 
@@ -1918,8 +1942,16 @@
 {
 	struct evhttp_connection *evcon = req->evcon;
 
+	if (evcon == NULL) {
+		evhttp_request_free(req);
+		return;
+	}
+
 	assert(TAILQ_FIRST(&evcon->requests) == req);
 
+	/* we expect no more calls form the user on this request */
+	req->userdone = 1;
+
 	/* xxx: not sure if we really should expose the data buffer this way */
 	if (databuf != NULL)
 		evbuffer_add_buffer(req->output_buffer, databuf);
@@ -1957,15 +1989,20 @@
 void
 evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
 {
+	struct evhttp_connection *evcon = req->evcon;
+
+	if (evcon == NULL)
+		return;
+
 	if (req->chunked) {
-		evbuffer_add_printf(req->evcon->output_buffer, "%x\r\n",
+		evbuffer_add_printf(evcon->output_buffer, "%x\r\n",
 				    (unsigned)EVBUFFER_LENGTH(databuf));
 	}
-	evbuffer_add_buffer(req->evcon->output_buffer, databuf);
+	evbuffer_add_buffer(evcon->output_buffer, databuf);
 	if (req->chunked) {
-		evbuffer_add(req->evcon->output_buffer, "\r\n", 2);
+		evbuffer_add(evcon->output_buffer, "\r\n", 2);
 	}
-	evhttp_write_buffer(req->evcon, NULL, NULL);
+	evhttp_write_buffer(evcon, NULL, NULL);
 }
 
 void
@@ -1973,6 +2010,14 @@
 {
 	struct evhttp_connection *evcon = req->evcon;
 
+	if (evcon == NULL) {
+		evhttp_request_free(req);
+		return;
+	}
+
+	/* we expect no more calls form the user on this request */
+	req->userdone = 1;
+
 	if (req->chunked) {
 		evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5);
 		evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
@@ -2190,8 +2235,15 @@
 	struct evhttp *http = arg;
 	struct evhttp_cb *cb = NULL;
 
+	event_debug(("%s: req->uri=%s", __func__, req->uri));
 	if (req->uri == NULL) {
-		evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
+		event_debug(("%s: bad request", __func__));
+		if (req->evcon->state == EVCON_DISCONNECTED) {
+			evhttp_connection_fail(req->evcon, EVCON_HTTP_EOF);
+		} else {
+			event_debug(("%s: sending error", __func__));
+			evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
+		}
 		return;
 	}
 
@@ -2505,6 +2557,13 @@
 	free(req);
 }
 
+struct evhttp_connection *
+evhttp_request_get_connection(struct evhttp_request *req)
+{
+	return req->evcon;
+}
+
+
 void
 evhttp_request_set_chunked_cb(struct evhttp_request *req,
     void (*cb)(struct evhttp_request *, void *))
diff --git a/third_party/libevent/install-sh b/third_party/libevent/install-sh
deleted file mode 100644
index 89fc9b0..0000000
--- a/third_party/libevent/install-sh
+++ /dev/null
@@ -1,238 +0,0 @@
-#! /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
index 556b73c..ee740ee 100644
--- a/third_party/libevent/kqueue.c
+++ b/third_party/libevent/kqueue.c
@@ -63,6 +63,7 @@
 #include "event.h"
 #include "event-internal.h"
 #include "log.h"
+#include "evsignal.h"
 
 #define EVLIST_X_KQINKERNEL	0x1000
 
@@ -140,6 +141,7 @@
 	}
 
 	/* Check for Mac OS X kqueue bug. */
+	memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
 	kqueueop->changes[0].ident = -1;
 	kqueueop->changes[0].filter = EVFILT_READ;
 	kqueueop->changes[0].flags = EV_ADD;
@@ -439,12 +441,15 @@
 {
 	struct kqop *kqop = arg;
 
+	evsignal_dealloc(base);
+
 	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/linux/event-config.h b/third_party/libevent/linux/event-config.h
index c8a6431..2203253 100644
--- a/third_party/libevent/linux/event-config.h
+++ b/third_party/libevent/linux/event-config.h
@@ -212,6 +212,13 @@
 /* Define if kqueue works correctly with pipes */
 /* #undef _EVENT_HAVE_WORKING_KQUEUE */
 
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
 /* Name of package */
 #define _EVENT_PACKAGE "libevent"
 
@@ -227,6 +234,9 @@
 /* Define to the one symbol short name of this package. */
 #define _EVENT_PACKAGE_TARNAME ""
 
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
 /* Define to the version of this package. */
 #define _EVENT_PACKAGE_VERSION ""
 
@@ -249,7 +259,7 @@
 #define _EVENT_TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define _EVENT_VERSION "1.4.13-stable"
+#define _EVENT_VERSION "1.4.15"
 
 /* Define to appropriate substitue if compiler doesnt have __func__ */
 /* #undef _EVENT___func__ */
diff --git a/third_party/libevent/ltmain.sh b/third_party/libevent/ltmain.sh
deleted file mode 100644
index 27d498a..0000000
--- a/third_party/libevent/ltmain.sh
+++ /dev/null
@@ -1,6956 +0,0 @@
-# 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/m4/.dummy b/third_party/libevent/m4/.dummy
new file mode 100644
index 0000000..a0a72d6
--- /dev/null
+++ b/third_party/libevent/m4/.dummy
@@ -0,0 +1 @@
+(This dummy file exists so that git will create the m4 directory)
diff --git a/third_party/libevent/mac/event-config.h b/third_party/libevent/mac/event-config.h
index 4af575a..92e212d 100644
--- a/third_party/libevent/mac/event-config.h
+++ b/third_party/libevent/mac/event-config.h
@@ -212,6 +212,13 @@
 /* Define if kqueue works correctly with pipes */
 #define _EVENT_HAVE_WORKING_KQUEUE 1
 
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
 /* Name of package */
 #define _EVENT_PACKAGE "libevent"
 
@@ -227,6 +234,9 @@
 /* Define to the one symbol short name of this package. */
 #define _EVENT_PACKAGE_TARNAME ""
 
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
 /* Define to the version of this package. */
 #define _EVENT_PACKAGE_VERSION ""
 
@@ -249,7 +259,7 @@
 #define _EVENT_TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define _EVENT_VERSION "1.4.13-stable"
+#define _EVENT_VERSION "1.4.15"
 
 /* Define to appropriate substitue if compiler doesnt have __func__ */
 /* #undef _EVENT___func__ */
diff --git a/third_party/libevent/min_heap.h b/third_party/libevent/min_heap.h
index 4fc83c0..14d8e37 100644
--- a/third_party/libevent/min_heap.h
+++ b/third_party/libevent/min_heap.h
@@ -56,7 +56,7 @@
 }
 
 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_dtor(min_heap_t* s) { if(s->p) 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; }
diff --git a/third_party/libevent/missing b/third_party/libevent/missing
deleted file mode 100644
index e7ef83a..0000000
--- a/third_party/libevent/missing
+++ /dev/null
@@ -1,360 +0,0 @@
-#! /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
deleted file mode 100644
index 56d6671..0000000
--- a/third_party/libevent/mkinstalldirs
+++ /dev/null
@@ -1,40 +0,0 @@
-#! /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/event-config.h b/third_party/libevent/nacl_nonsfi/event-config.h
index 636ee80..fe28043 100644
--- a/third_party/libevent/nacl_nonsfi/event-config.h
+++ b/third_party/libevent/nacl_nonsfi/event-config.h
@@ -211,6 +211,13 @@
 /* Define if kqueue works correctly with pipes */
 /* #undef _EVENT_HAVE_WORKING_KQUEUE */
 
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
 /* Name of package */
 #define _EVENT_PACKAGE "libevent_nacl"
 
@@ -226,6 +233,9 @@
 /* Define to the one symbol short name of this package. */
 #define _EVENT_PACKAGE_TARNAME ""
 
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
 /* Define to the version of this package. */
 #define _EVENT_PACKAGE_VERSION ""
 
@@ -248,7 +258,7 @@
 #define _EVENT_TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define _EVENT_VERSION "1.4.13-stable"
+#define _EVENT_VERSION "1.4.15"
 
 /* Define to appropriate substitue if compiler doesnt have __func__ */
 /* #undef _EVENT___func__ */
diff --git a/third_party/libevent/sample/Makefile.in b/third_party/libevent/sample/Makefile.in
deleted file mode 100644
index 793752a..0000000
--- a/third_party/libevent/sample/Makefile.in
+++ /dev/null
@@ -1,442 +0,0 @@
-# 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
index 2c6cb93..0a439ce 100644
--- a/third_party/libevent/sample/event-test.c
+++ b/third_party/libevent/sample/event-test.c
@@ -73,7 +73,7 @@
 #ifdef WIN32
 	HANDLE socket;
 	// Open a file. 
-	socket = CreateFile("test.txt",     // open File 
+	socket = CreateFileA("test.txt",     // open File 
 			GENERIC_READ,                 // open for reading 
 			0,                            // do not share 
 			NULL,                         // no security 
diff --git a/third_party/libevent/sample/signal-test.c b/third_party/libevent/sample/signal-test.c
index 9a131cb..5a5a303 100644
--- a/third_party/libevent/sample/signal-test.c
+++ b/third_party/libevent/sample/signal-test.c
@@ -38,7 +38,7 @@
 
 	if (called >= 2)
 		event_del(signal);
-	
+
 	called++;
 }
 
@@ -46,17 +46,19 @@
 main (int argc, char **argv)
 {
 	struct event signal_int;
- 
+
 	/* Initalize the event library */
-	event_init();
+	struct event_base* base = event_base_new();
 
 	/* Initalize one event */
 	event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,
 	    &signal_int);
+	event_base_set(base, &signal_int);
 
 	event_add(&signal_int, NULL);
 
-	event_dispatch();
+	event_base_dispatch(base);
+	event_base_free(base);
 
 	return (0);
 }
diff --git a/third_party/libevent/signal.c b/third_party/libevent/signal.c
index 74fa23f..b8d51ab 100644
--- a/third_party/libevent/signal.c
+++ b/third_party/libevent/signal.c
@@ -67,6 +67,13 @@
 
 static void evsignal_handler(int sig);
 
+#ifdef WIN32
+#define error_is_eagain(err)			\
+	((err) == EAGAIN || (err) == WSAEWOULDBLOCK)
+#else
+#define error_is_eagain(err) ((err) == EAGAIN)
+#endif
+
 /* Callback for when the signal handler write a byte to our signaling socket */
 static void
 evsignal_cb(int fd, short what, void *arg)
@@ -79,8 +86,11 @@
 #endif
 
 	n = recv(fd, signals, sizeof(signals), 0);
-	if (n == -1)
-		event_err(1, "%s: read", __func__);
+	if (n == -1) {
+		int err = EVUTIL_SOCKET_ERROR();
+		if (! error_is_eagain(err))
+			event_err(1, "%s: read", __func__);
+	}
 }
 
 #ifdef HAVE_SETFD
@@ -125,6 +135,7 @@
 		TAILQ_INIT(&base->sig.evsigevents[i]);
 
         evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
+        evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]);
 
 	event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1],
 		EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal);
@@ -186,12 +197,14 @@
 	if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
 		event_warn("sigaction");
 		free(sig->sh_old[evsignal]);
+		sig->sh_old[evsignal] = NULL;
 		return (-1);
 	}
 #else
 	if ((sh = signal(evsignal, handler)) == SIG_ERR) {
 		event_warn("signal");
 		free(sig->sh_old[evsignal]);
+		sig->sh_old[evsignal] = NULL;
 		return (-1);
 	}
 	*sig->sh_old[evsignal] = sh;
@@ -346,12 +359,19 @@
 			_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;
+	if (base->sig.ev_signal_pair[0] != -1) {
+		EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
+		base->sig.ev_signal_pair[0] = -1;
+	}
+	if (base->sig.ev_signal_pair[1] != -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);
+	/* per index frees are handled in evsig_del() */
+	if (base->sig.sh_old) {
+		free(base->sig.sh_old);
+		base->sig.sh_old = NULL;
+	}
 }
diff --git a/third_party/libevent/solaris/event-config.h b/third_party/libevent/solaris/event-config.h
index c5fe160..afabe2f 100644
--- a/third_party/libevent/solaris/event-config.h
+++ b/third_party/libevent/solaris/event-config.h
@@ -212,6 +212,13 @@
 /* Define if kqueue works correctly with pipes */
 /* #undef _EVENT_HAVE_WORKING_KQUEUE */
 
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
 /* Name of package */
 #define _EVENT_PACKAGE "libevent"
 
@@ -227,6 +234,9 @@
 /* Define to the one symbol short name of this package. */
 #define _EVENT_PACKAGE_TARNAME ""
 
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
 /* Define to the version of this package. */
 #define _EVENT_PACKAGE_VERSION ""
 
@@ -249,7 +259,7 @@
 #define _EVENT_TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define _EVENT_VERSION "1.4.13-stable"
+#define _EVENT_VERSION "1.4.15"
 
 /* Define to appropriate substitue if compiler doesnt have __func__ */
 /* #undef _EVENT___func__ */
diff --git a/third_party/libevent/stamp-h.in b/third_party/libevent/stamp-h.in
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/third_party/libevent/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/third_party/libevent/test/Makefile.in b/third_party/libevent/test/Makefile.in
deleted file mode 100644
index c2d5b31..0000000
--- a/third_party/libevent/test/Makefile.in
+++ /dev/null
@@ -1,487 +0,0 @@
-# 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/Makefile.nmake b/third_party/libevent/test/Makefile.nmake
new file mode 100644
index 0000000..320abe7
--- /dev/null
+++ b/third_party/libevent/test/Makefile.nmake
@@ -0,0 +1,47 @@
+
+CFLAGS=/I.. /I../include /I../WIN32-Code /I../compat /DWIN32 /DHAVE_CONFIG_H
+
+CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
+
+REGRESS_OBJS=regress.obj regress_http.obj regress_dns.obj \
+        regress_rpc.obj regress.gen.obj \
+
+OTHER_OBJS=test-init.obj test-eof.obj test-weof.obj test-time.obj \
+	bench.obj bench_cascade.obj bench_http.obj bench_httpclient.obj
+
+PROGRAMS=regress.exe \
+	test-init.exe test-eof.exe test-weof.exe test-time.exe
+
+# Disabled for now:
+#	bench.exe bench_cascade.exe bench_http.exe bench_httpclient.exe
+
+
+LIBS=..\libevent.lib ws2_32.lib advapi32.lib
+
+all: $(PROGRAMS)
+
+regress.exe: $(REGRESS_OBJS)
+	$(CC) $(CFLAGS) $(LIBS) $(REGRESS_OBJS)
+
+test-init.exe: test-init.obj
+	$(CC) $(CFLAGS) $(LIBS) test-init.obj
+test-eof.exe: test-eof.obj
+	$(CC) $(CFLAGS) $(LIBS) test-eof.obj
+test-weof.exe: test-weof.obj
+	$(CC) $(CFLAGS) $(LIBS) test-weof.obj
+test-time.exe: test-time.obj
+	$(CC) $(CFLAGS) $(LIBS) test-time.obj
+
+bench.exe: bench.obj
+	$(CC) $(CFLAGS) $(LIBS) bench.obj
+bench_cascade.exe: bench_cascade.obj
+	$(CC) $(CFLAGS) $(LIBS) bench_cascade.obj
+bench_http.exe: bench_http.obj
+	$(CC) $(CFLAGS) $(LIBS) bench_http.obj
+bench_httpclient.exe: bench_httpclient.obj
+	$(CC) $(CFLAGS) $(LIBS) bench_httpclient.obj
+
+clean:
+	-del $(REGRESS_OBJS)
+	-del $(OTHER_OBJS)
+	-del regress.exe
diff --git a/third_party/libevent/test/regress.c b/third_party/libevent/test/regress.c
index 0b7517d..cce7d7d 100644
--- a/third_party/libevent/test/regress.c
+++ b/third_party/libevent/test/regress.c
@@ -1020,6 +1020,205 @@
 }
 
 static void
+test_evbuffer_readln(void)
+{
+	struct evbuffer *evb = evbuffer_new();
+	struct evbuffer *evb_tmp = evbuffer_new();
+	const char *s;
+	char *cp = NULL;
+	size_t sz;
+
+#define tt_line_eq(content)						\
+	if (!cp || sz != strlen(content) || strcmp(cp, content)) {	\
+		fprintf(stdout, "FAILED\n");				\
+		exit(1);						\
+	}
+#define tt_assert(expression)						\
+	if (!(expression)) {						\
+		fprintf(stdout, "FAILED\n");				\
+		exit(1);						\
+	}								\
+
+	/* Test EOL_ANY. */
+	fprintf(stdout, "Testing evbuffer_readln EOL_ANY: ");
+
+	s = "complex silly newline\r\n\n\r\n\n\rmore\0\n";
+	evbuffer_add(evb, s, strlen(s)+2);
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+	tt_line_eq("complex silly newline");
+	free(cp);
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+	if (!cp || sz != 5 || memcmp(cp, "more\0\0", 6)) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+	if (evb->totallen == 0) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+	s = "\nno newline";
+	evbuffer_add(evb, s, strlen(s));
+	free(cp);
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+	tt_line_eq("");
+	free(cp);
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
+        tt_assert(!cp);
+	evbuffer_drain(evb, EVBUFFER_LENGTH(evb));
+        tt_assert(EVBUFFER_LENGTH(evb) == 0);
+
+	fprintf(stdout, "OK\n");
+
+	/* Test EOL_CRLF */
+	fprintf(stdout, "Testing evbuffer_readln EOL_CRLF: ");
+
+	s = "Line with\rin the middle\nLine with good crlf\r\n\nfinal\n";
+	evbuffer_add(evb, s, strlen(s));
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+	tt_line_eq("Line with\rin the middle");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+	tt_line_eq("Line with good crlf");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+	tt_line_eq("");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+	tt_line_eq("final");
+	s = "x";
+	evbuffer_add(evb, s, 1);
+	free(cp);
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
+        tt_assert(!cp);
+
+	fprintf(stdout, "OK\n");
+
+	/* Test CRLF_STRICT */
+	fprintf(stdout, "Testing evbuffer_readln CRLF_STRICT: ");
+
+	s = " and a bad crlf\nand a good one\r\n\r\nMore\r";
+	evbuffer_add(evb, s, strlen(s));
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_line_eq("x and a bad crlf\nand a good one");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_line_eq("");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+        tt_assert(!cp);
+	evbuffer_add(evb, "\n", 1);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_line_eq("More");
+	free(cp);
+	tt_assert(EVBUFFER_LENGTH(evb) == 0);
+
+	s = "An internal CR\r is not an eol\r\nNor is a lack of one";
+	evbuffer_add(evb, s, strlen(s));
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_line_eq("An internal CR\r is not an eol");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_assert(!cp);
+
+	evbuffer_add(evb, "\r\n", 2);
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_line_eq("Nor is a lack of one");
+	free(cp);
+	tt_assert(EVBUFFER_LENGTH(evb) == 0);
+
+	fprintf(stdout, "OK\n");
+
+	/* Test LF */
+	fprintf(stdout, "Testing evbuffer_readln LF: ");
+
+	s = "An\rand a nl\n\nText";
+	evbuffer_add(evb, s, strlen(s));
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+	tt_line_eq("An\rand a nl");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+	tt_line_eq("");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+	tt_assert(!cp);
+	free(cp);
+	evbuffer_add(evb, "\n", 1);
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+	tt_line_eq("Text");
+	free(cp);
+
+	fprintf(stdout, "OK\n");
+
+	/* Test CRLF_STRICT - across boundaries */
+	fprintf(stdout,
+	    "Testing evbuffer_readln CRLF_STRICT across boundaries: ");
+
+	s = " and a bad crlf\nand a good one\r";
+	evbuffer_add(evb_tmp, s, strlen(s));
+	evbuffer_add_buffer(evb, evb_tmp);
+	s = "\n\r";
+	evbuffer_add(evb_tmp, s, strlen(s));
+	evbuffer_add_buffer(evb, evb_tmp);
+	s = "\nMore\r";
+	evbuffer_add(evb_tmp, s, strlen(s));
+	evbuffer_add_buffer(evb, evb_tmp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_line_eq(" and a bad crlf\nand a good one");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_line_eq("");
+	free(cp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_assert(!cp);
+	free(cp);
+	evbuffer_add(evb, "\n", 1);
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
+	tt_line_eq("More");
+	free(cp); cp = NULL;
+	if (EVBUFFER_LENGTH(evb) != 0) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+
+	/* Test memory problem */
+	fprintf(stdout, "Testing evbuffer_readln memory problem: ");
+
+	s = "one line\ntwo line\nblue line";
+	evbuffer_add(evb_tmp, s, strlen(s));
+	evbuffer_add_buffer(evb, evb_tmp);
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+	tt_line_eq("one line");
+	free(cp); cp = NULL;
+
+	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
+	tt_line_eq("two line");
+	free(cp); cp = NULL;
+
+	fprintf(stdout, "OK\n");
+
+	test_ok = 1;
+	evbuffer_free(evb);
+	evbuffer_free(evb_tmp);
+	if (cp) free(cp);
+}
+
+static void
 test_evbuffer_find(void)
 {
 	u_char* p;
@@ -1640,6 +1839,7 @@
 
 	test_evbuffer();
 	test_evbuffer_find();
+	test_evbuffer_readln();
 	
 	test_bufferevent();
 	test_bufferevent_watermarks();
diff --git a/third_party/libevent/test/regress.gen.c b/third_party/libevent/test/regress.gen.c
deleted file mode 100644
index 0918fc0..0000000
--- a/third_party/libevent/test/regress.gen.c
+++ /dev/null
@@ -1,878 +0,0 @@
-/*
- * 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
deleted file mode 100644
index b1feacd..0000000
--- a/third_party/libevent/test/regress.gen.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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_http.c b/third_party/libevent/test/regress_http.c
index 1e2a1eb..943b29d 100644
--- a/third_party/libevent/test/regress_http.c
+++ b/third_party/libevent/test/regress_http.c
@@ -71,6 +71,7 @@
 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 void http_badreq_cb(struct evhttp_request *req, void *arg);
 
 static struct evhttp *
 http_setup(short *pport, struct event_base *base)
@@ -96,6 +97,7 @@
 	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, "/badrequest", http_badreq_cb, NULL);
 	evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL);
 
 	*pport = port;
@@ -377,6 +379,155 @@
 	fprintf(stdout, "OK\n");
 }
 
+static void
+http_badreq_cb(struct evhttp_request *req, void *arg)
+{
+	struct evbuffer *buf = evbuffer_new();
+
+	evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charset=UTF-8");
+	evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
+
+	evhttp_send_reply(req, HTTP_OK, "OK", buf);
+	evbuffer_free(buf);
+}
+
+static void
+http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+	/* ignore */
+}
+
+static void
+http_badreq_readcb(struct bufferevent *bev, void *arg)
+{
+	const char *what = "Hello, 127.0.0.1";
+	const char *bad_request = "400 Bad Request";
+
+	event_debug(("%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
+
+	if (evbuffer_find(bev->input,
+		(const unsigned char *) bad_request, strlen(bad_request)) != NULL) {
+		event_debug(("%s: bad request detected", __func__));
+		test_ok = -10;
+		bufferevent_disable(bev, EV_READ);
+		event_loopexit(NULL);
+		return;
+	}
+
+	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);
+		evbuffer_drain(bev->input, EVBUFFER_LENGTH(bev->input));
+	}
+
+	shutdown(bev->ev_read.ev_fd, SHUT_WR);
+}
+
+static void
+http_badreq_successcb(int fd, short what, void *arg)
+{
+	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+	event_loopexit(NULL);
+}
+
+static void
+http_bad_request(void)
+{
+	struct timeval tv;
+	struct bufferevent *bev;
+	int fd;
+	const char *http_request;
+	short port = -1;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing \"Bad Request\" on connection close: ");
+
+	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);
+	}
+
+	/* NULL request test */
+	fd = http_connect("127.0.0.1", port);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, http_badreq_readcb, http_writecb,
+	    http_badreq_errorcb, NULL);
+	bufferevent_enable(bev, EV_READ);
+
+	/* real NULL request */
+	http_request = "";
+
+	shutdown(fd, SHUT_WR);
+	timerclear(&tv);
+	tv.tv_usec = 10000;
+	event_once(-1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
+
+	event_dispatch();
+
+	bufferevent_free(bev);
+	EVUTIL_CLOSESOCKET(fd);
+
+	if (test_ok != 0) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* Second answer (BAD REQUEST) on connection close */
+
+	/* connect to the second port */
+	fd = http_connect("127.0.0.1", port + 1);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, http_badreq_readcb, http_writecb,
+	    http_badreq_errorcb, NULL);
+	bufferevent_enable(bev, EV_READ);
+
+	/* first half of the http request */
+	http_request =
+		"GET /badrequest HTTP/1.0\r\n"	\
+		"Connection: Keep-Alive\r\n"	\
+		"\r\n";
+
+	bufferevent_write(bev, http_request, strlen(http_request));
+
+	timerclear(&tv);
+	tv.tv_usec = 10000;
+	event_once(-1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
+
+	event_dispatch();
+
+	evhttp_free(http);
+
+	if (test_ok != 2) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+}
 static struct evhttp_connection *delayed_client;
 
 static void
@@ -1453,6 +1604,121 @@
 	fprintf(stdout, "OK\n");
 }
 
+/*
+ * Testing client reset of server chunked connections
+ */
+
+struct terminate_state {
+	struct evhttp_request *req;
+	struct bufferevent *bev;
+	int fd;
+} terminate_state;
+
+static void
+terminate_chunked_trickle_cb(int fd, short events, void *arg)
+{
+	struct terminate_state *state = arg;
+	struct evbuffer *evb = evbuffer_new();
+	struct timeval tv;
+
+	if (evhttp_request_get_connection(state->req) == NULL) {
+		test_ok = 1;
+		evhttp_request_free(state->req);
+		event_loopexit(NULL);
+		return;
+	}
+
+	evbuffer_add_printf(evb, "%p", evb);
+	evhttp_send_reply_chunk(state->req, evb);
+	evbuffer_free(evb);
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 3000;
+	event_once(-1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
+}
+
+static void
+terminate_chunked_cb(struct evhttp_request *req, void *arg)
+{
+	struct terminate_state *state = arg;
+	struct timeval tv;
+
+	state->req = req;
+
+	evhttp_send_reply_start(req, HTTP_OK, "OK");
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 3000;
+	event_once(-1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
+}
+
+static void
+terminate_chunked_client(int fd, short event, void *arg)
+{
+	struct terminate_state *state = arg;
+	bufferevent_free(state->bev);
+	EVUTIL_CLOSESOCKET(state->fd);
+}
+
+static void
+terminate_readcb(struct bufferevent *bev, void *arg)
+{
+	/* just drop the data */
+	evbuffer_drain(bev->output, -1);
+}
+
+
+static void
+http_terminate_chunked_test(void)
+{
+	struct bufferevent *bev = NULL;
+	struct timeval tv;
+	const char *http_request;
+	short port = -1;
+	int fd = -1;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing Terminated Chunked Connection: ");
+
+	http = http_setup(&port, NULL);
+	evhttp_del_cb(http, "/test");
+	evhttp_set_cb(http, "/test", terminate_chunked_cb, &terminate_state);
+
+	fd = http_connect("127.0.0.1", port);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, terminate_readcb, http_writecb,
+	    http_errorcb, NULL);
+
+	terminate_state.fd = fd;
+	terminate_state.bev = bev;
+
+	/* first half of the http request */
+	http_request =
+	    "GET /test HTTP/1.1\r\n"
+	    "Host: some\r\n\r\n";
+
+	bufferevent_write(bev, http_request, strlen(http_request));
+	evutil_timerclear(&tv);
+	tv.tv_usec = 10000;
+	event_once(-1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
+	    &tv);
+
+	event_dispatch();
+
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+
+	if (fd >= 0)
+		EVUTIL_CLOSESOCKET(fd);
+	if (http)
+		evhttp_free(http);
+}
+
 void
 http_suite(void)
 {
@@ -1462,8 +1728,9 @@
 	http_basic_test();
 	http_connection_test(0 /* not-persistent */);
 	http_connection_test(1 /* persistent */);
-	http_close_detection(0 /* with delay */);
+	http_close_detection(0 /* without delay */);
 	http_close_detection(1 /* with delay */);
+	http_bad_request();
 	http_post_test();
 	http_failure_test();
 	http_highport_test();
@@ -1473,4 +1740,5 @@
 	http_negative_content_length_test();
 
 	http_chunked_test();
+	http_terminate_chunked_test();
 }
diff --git a/third_party/libevent/test/test.sh b/third_party/libevent/test/test.sh
old mode 100644
new mode 100755
diff --git a/third_party/libevent/whatsnew-14.txt b/third_party/libevent/whatsnew-14.txt
new file mode 100644
index 0000000..769dda7
--- /dev/null
+++ b/third_party/libevent/whatsnew-14.txt
@@ -0,0 +1,167 @@
+What's New In Libevent 1.4:
+
+0. About this document
+
+  This document describes the key differences between Libevent 1.3 and
+  Libevent 1.4, from a user's point of view.  It was most recently
+  updated based on features from libevent 1.4.2-rc.
+
+1. Packaging Issues.
+
+1.1. The great library division.
+
+  The libevent source now builds two libraries: libevent_core and
+  libevent_extra.  The libevent_core library includes event loops,
+  timers, buffer code, and various small compatibility functions.  The
+  libevent_extra library includes code for HTTP, DNS, RPC, and so on.
+  Thus, if you're writing software that only uses libevent's event
+  loop, you should link against only the libevent_core library,
+  whereas if you're writing software that uses libevent's protocol
+  support as well, you need to link libevent_extra as well.
+
+  For backward compatibility, libevent also builds a library called
+  "libevent" that includes everything.
+
+1.2. The event-config.h header
+
+  Libevent configure script now builds two headers from its configure
+  script: config.h (which it uses internally) and event-config.h
+  (which it installs as a header file).  All of the macros in
+  event-config.h are modified so that they're safe to include in other
+  projects.  This allows libevent's header files (like event.h and
+  evutil.h) information about platform configuration.
+
+  What does this mean for you?  As of 1.4.x, it should never be
+  necessary to include extra files or define extra types before you
+  include event.h (or any other libevent header); event.h can now look
+  at the information in event-config.h and figure out what it needs to
+  include.
+
+1.3. Documentation
+
+  Libevent now includes better doxygen documentation.  It's not
+  perfect or complete, though; if you find a mistake, please let us
+  know.
+
+1.4. Libtool usage
+
+  We now use libtool's library versioning support correctly.  If we
+  don't mess this up, it means that binaries linked against old
+  version of libevent should continue working when we make changes to
+  libevent that don't break backward compatibility.
+
+1.5. Portability
+
+  Libevent now builds with MSVC again.  We've only tested it with MSVC
+  2005, and the project files might not be right.  Please let us know
+  if you run into any issues.
+
+  Libevent now builds on platforms where /bin/sh is not bash.
+
+  Libevent's regression test no longer requires Python to be
+  installed.
+
+2. New and Improved APIs:
+
+  (This list includes functions that are new, functions whose behavior
+  has changed, and functions that were included in previous releases
+  but which never actually worked before.)
+
+2.1. Utility functions are defined in evutil.h
+
+  Libevent now exposes a small set of functions for cross-platform
+  network programming in evutil.h, on the theory that they've been
+  useful enough to us that other people may likely want to use them
+  too.  These are mainly workarounds for Windows issues for now: they
+  include evutil_socketpair (to fake socketpair on platforms that
+  don't have it) and evutil_make_socket_nonblocking (to make a socket
+  nonblocking in a cross-platform way.  See the header for more
+  information.
+
+2.2. In the libevent core.
+
+  The event_base_free() function now works.  Previously, it would
+  crash with an assertion failure if there were events pending on a
+  base.  Now, it simply deletes all the pending events and frees the
+  base.  Be careful -- this might leak fds and memory associated with
+  the old events.  To avoid leaks, you should still remove all the
+  events and free their resources before you delete the base.
+
+  Libevent should now work properly with fork().  Just call
+  event_reinit() on your event base after the fork call, and it should
+  work okay.  Please let us know about any bugs you find.
+
+  There's a new event_base_new() function that acts just like
+  event_init(), but does not replace the default base.  If you are
+  using multiple event bases in your code, you should just use
+  event_base_new() instead of event_init(), to avoid accidental bugs.
+
+  There's new event_loopbreak() function to make a current event loop
+  stop exiting and return.  Unlike event_loopexit, it stops subsequent
+  pending events from getting executed.  This behavior is useful for
+  scripting languages to implement exceptions from inside callbacks.
+
+  There's a new event_base_get_method() function, for use in place of
+  event_get_method() in multi-base applications.
+
+2.3. New in HTTP.
+
+  There's an evhttp_connection_set_local_address() function you can
+  use to set the local address of an HTTP connection.
+
+  HTTP/1.1 chunking now correctly ends chunks with '\r\n'.
+
+2.4. New in DNS
+
+  Instead of picking your method for generating DNS transaction IDs at
+  startup, you can use evdns_set_transaction_id() to provide a
+  transaction ID function at runtime.
+
+  The "class" field in evdns_server_request is now renamed to
+  dns_question_class, so that it won't break compilation under C++.
+  This uses some preprocessor hacks so that C code using the old name
+  won't break.  Eventually, the old name will be deprecated entirely;
+  please don't use it.
+
+2.5. New in RPC
+
+  There are now hooks on RPC input and output; can be used to
+  implement RPC independent processing such as compression or
+  authentication.
+
+  RPC tags can now be up to 32 bits.  This is wire-compatible, but
+  changes some of the types in the APIs.  Please let us know if this
+  is problematic for you.
+
+3. Big bugfixes
+
+  We've done a lot, with help from users on different platforms, to
+  make the different backends behave more similarly with respect to
+  signals and timeouts.  The kqueue and solaris backends were the big
+  offenders previously, but they should be better now.  Windows should
+  be better too, though it's likely that problems remain there.
+
+  The libevent headers (though not the source files!) should now build
+  cleanly on C++.
+
+  (For more bugfixes, see the ChangeLog file.  These are only the
+  biggies.)
+
+4. Big performance improvements
+
+  Libevent now uses a min-heap rather than a red-black tree to track
+  timeouts.  This means that finding the next timeout to fire is now
+  O(1) instead of (lg n).
+
+  The win32 select-based backend now uses a red-black tree to map
+  SOCKET handles to event structures.  This changes the performance
+  characteristics of the event loop on win32 from O(n^2) to O(n lg n).
+  Not perfect, but better.
+
+5. Removed code and features
+
+  The rtsig backend is now removed.  It hasn't even compiled for a
+  while, and nobody seemed to miss it very much.  All the platforms
+  that have rtsig seem to have a better option instead these days.
+  Please let us know if rtsig was crucial for you.
+
diff --git a/third_party/modp_b64/README.chromium b/third_party/modp_b64/README.chromium
index 35b9e54..364a050 100644
--- a/third_party/modp_b64/README.chromium
+++ b/third_party/modp_b64/README.chromium
@@ -1,6 +1,6 @@
 Name: modp base64 decoder
 Short Name: stringencoders
-URL: http://code.google.com/p/stringencoders/
+URL: https://github.com/client9/stringencoders
 Version: unknown
 License: BSD
 Security Critical: yes
@@ -13,3 +13,5 @@
 
 The modp_b64.cc and modp_b64.h files were modified to make them safe on
 64-bit systems.
+The modp_b64.cc was modified to avoid misaligned read/write on
+little-endian hardware.
diff --git a/third_party/modp_b64/modp_b64.cc b/third_party/modp_b64/modp_b64.cc
index e5f6cf1..fdb8a40 100644
--- a/third_party/modp_b64/modp_b64.cc
+++ b/third_party/modp_b64/modp_b64.cc
@@ -211,28 +211,18 @@
 
     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];
-
+    const uint8_t* y = (uint8_t*)src;
+    for (i = 0; i < chunks; ++i, y += 4) {
+        x = d0[y[0]] | d1[y[1]] | d2[y[2]] | d3[y[3]];
         if (x >= BADCHAR) return MODP_B64_ERROR;
-        *destInt = x ;
-        p += 3;
-        destInt = (uint32_t*)p;
-        y = *srcInt++;}
-
+        *p++ =  ((uint8_t*)(&x))[0];
+        *p++ =  ((uint8_t*)(&x))[1];
+        *p++ =  ((uint8_t*)(&x))[2];
+    }
 
     switch (leftover) {
     case 0:
-        x = d0[y & 0xff] |
-            d1[(y >> 8) & 0xff] |
-            d2[(y >> 16) & 0xff] |
-            d3[(y >> 24) & 0xff];
+        x = d0[y[0]] | d1[y[1]] | d2[y[2]] | d3[y[3]];
 
         if (x >= BADCHAR) return MODP_B64_ERROR;
         *p++ =  ((uint8_t*)(&x))[0];
@@ -241,17 +231,15 @@
         return (chunks+1)*3;
         break;
     case 1:  /* with padding this is an impossible case */
-        x = d0[y & 0xff];
+        x = d0[y[0]];
         *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];
+        x = d0[y[0]] | d1[y[1]];
         *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 */
+        x = d0[y[0]] | d1[y[1]] | d2[y[2]];  /* 0x3c */
         *p++ =  ((uint8_t*)(&x))[0];
         *p =  ((uint8_t*)(&x))[1];
         break;
diff --git a/third_party/modp_b64/modp_b64_nacl.gyp b/third_party/modp_b64/modp_b64_nacl.gyp
index e2f4a25..ceea2e1 100644
--- a/third_party/modp_b64/modp_b64_nacl.gyp
+++ b/third_party/modp_b64/modp_b64_nacl.gyp
@@ -15,6 +15,7 @@
         'build_glibc': 0,
         'build_newlib': 1,
         'build_pnacl_newlib': 1,
+        'nacl_untrusted_build': 1,
       },
       'sources': [
         'modp_b64.cc',
diff --git a/tools/clang/scripts/blink_gc_plugin_flags.py b/tools/clang/scripts/blink_gc_plugin_flags.py
index 5bb28da..0b3e82b 100755
--- a/tools/clang/scripts/blink_gc_plugin_flags.py
+++ b/tools/clang/scripts/blink_gc_plugin_flags.py
@@ -15,18 +15,27 @@
 
 FLAGS = '-Xclang -add-plugin -Xclang blink-gc-plugin'
 PREFIX= ' -Xclang -plugin-arg-blink-gc-plugin -Xclang '
+
+warn_raw_pointers = None
 for arg in sys.argv[1:]:
   if arg == 'enable-oilpan=1':
     FLAGS += PREFIX + 'enable-oilpan'
+    if warn_raw_pointers is None:
+      warn_raw_pointers = True
   elif arg == 'dump-graph=1':
     FLAGS += PREFIX + 'dump-graph'
   elif arg == 'warn-raw-ptr=1':
-    FLAGS += PREFIX + 'warn-raw-ptr'
+    warn_raw_pointers = True
+  elif arg == 'warn-raw-ptr=0':
+    warn_raw_pointers = False
   elif arg == 'warn-unneeded-finalizer=1':
     FLAGS += PREFIX + 'warn-unneeded-finalizer'
   elif arg.startswith('custom_clang_lib_path='):
     CLANG_LIB_PATH = arg[len('custom_clang_lib_path='):]
 
+if warn_raw_pointers is True:
+  FLAGS += PREFIX + 'warn-raw-ptr'
+
 if not sys.platform in ['win32', 'cygwin']:
   LIBSUFFIX = 'dylib' if sys.platform == 'darwin' else 'so'
   FLAGS = ('-Xclang -load -Xclang "%s/libBlinkGCPlugin.%s" ' + FLAGS) % \
diff --git a/tools/clang/scripts/blink_gc_plugin_flags.sh b/tools/clang/scripts/blink_gc_plugin_flags.sh
deleted file mode 100755
index 1c883c5..0000000
--- a/tools/clang/scripts/blink_gc_plugin_flags.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/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.
-
-# TODO(thakis): Remove this script once Source/config.gyp refers the the .py
-# file.
-THIS_DIR="$(dirname "${0}")"
-ABS_THIS_DIR="${PWD}/${THIS_DIR}"
-exec python "${ABS_THIS_DIR}/blink_gc_plugin_flags.py" "$@"
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
new file mode 100755
index 0000000..a758a7b
--- /dev/null
+++ b/tools/clang/scripts/package.py
@@ -0,0 +1,244 @@
+#!/usr/bin/env python
+# 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 script will check out llvm and clang, and then package the results up
+to a tgz file."""
+
+import argparse
+import fnmatch
+import itertools
+import os
+import shutil
+import subprocess
+import sys
+import tarfile
+
+# Path constants.
+THIS_DIR = os.path.dirname(__file__)
+THIRD_PARTY_DIR = os.path.join(THIS_DIR, '..', '..', '..', 'third_party')
+LLVM_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm')
+LLVM_BOOTSTRAP_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-bootstrap')
+LLVM_BOOTSTRAP_INSTALL_DIR = os.path.join(THIRD_PARTY_DIR,
+                                          'llvm-bootstrap-install')
+LLVM_BUILD_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-build')
+LLVM_RELEASE_DIR = os.path.join(LLVM_BUILD_DIR, 'Release+Asserts')
+STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
+
+
+def Tee(output, logfile):
+  logfile.write(output)
+  print output,
+
+
+def TeeCmd(cmd, logfile, fail_hard=True):
+  """Runs cmd and writes the output to both stdout and logfile."""
+  # Reading from PIPE can deadlock if one buffer is full but we wait on a
+  # different one.  To work around this, pipe the subprocess's stderr to
+  # its stdout buffer and don't give it a stdin.
+  # shell=True is required in cmd.exe since depot_tools has an svn.bat, and
+  # bat files only work with shell=True set.
+  proc = subprocess.Popen(cmd, bufsize=1, shell=sys.platform == 'win32',
+                          stdin=open(os.devnull), stdout=subprocess.PIPE,
+                          stderr=subprocess.STDOUT)
+  for line in iter(proc.stdout.readline,''):
+    Tee(line, logfile)
+    if proc.poll() is not None:
+      break
+  exit_code = proc.wait()
+  if exit_code != 0 and fail_hard:
+    print 'Failed:', cmd
+    sys.exit(1)
+
+
+def PrintTarProgress(tarinfo):
+  print 'Adding', tarinfo.name
+  return tarinfo
+
+
+def main():
+  if sys.platform == 'win32':
+    try:
+      subprocess.check_output(['grep', '--help'], shell=True)
+    except subprocess.CalledProcessError:
+      print 'Add gnuwin32 to your PATH, then try again.'
+      return 1
+
+  parser = argparse.ArgumentParser(description='build and package clang')
+  parser.add_argument('--gcc-toolchain',
+                      help="the prefix for the GCC version used for building. "
+                           "For /opt/foo/bin/gcc, pass "
+                           "'--gcc-toolchain '/opt/foo'")
+
+  args = parser.parse_args()
+
+  with open('buildlog.txt', 'w') as log:
+    Tee('Diff in llvm:\n', log)
+    TeeCmd(['svn', 'stat', LLVM_DIR], log, fail_hard=False)
+    TeeCmd(['svn', 'diff', LLVM_DIR], log, fail_hard=False)
+    Tee('Diff in llvm/tools/clang:\n', log)
+    TeeCmd(['svn', 'stat', os.path.join(LLVM_DIR, 'tools', 'clang')],
+           log, fail_hard=False)
+    TeeCmd(['svn', 'diff', os.path.join(LLVM_DIR, 'tools', 'clang')],
+           log, fail_hard=False)
+    # TODO(thakis): compiler-rt is in projects/compiler-rt on Windows but
+    # llvm/compiler-rt elsewhere. So this diff call is currently only right on
+    # Windows.
+    Tee('Diff in llvm/compiler-rt:\n', log)
+    TeeCmd(['svn', 'stat', os.path.join(LLVM_DIR, 'projects', 'compiler-rt')],
+           log, fail_hard=False)
+    TeeCmd(['svn', 'diff', os.path.join(LLVM_DIR, 'projects', 'compiler-rt')],
+           log, fail_hard=False)
+    Tee('Diff in llvm/projects/libcxx:\n', log)
+    TeeCmd(['svn', 'stat', os.path.join(LLVM_DIR, 'projects', 'libcxx')],
+           log, fail_hard=False)
+    TeeCmd(['svn', 'diff', os.path.join(LLVM_DIR, 'projects', 'libcxx')],
+           log, fail_hard=False)
+    Tee('Diff in llvm/projects/libcxxabi:\n', log)
+    TeeCmd(['svn', 'stat', os.path.join(LLVM_DIR, 'projects', 'libcxxabi')],
+           log, fail_hard=False)
+    TeeCmd(['svn', 'diff', os.path.join(LLVM_DIR, 'projects', 'libcxxabi')],
+           log, fail_hard=False)
+
+    Tee('Starting build\n', log)
+
+    # Do a clobber build.
+    shutil.rmtree(LLVM_BOOTSTRAP_DIR, ignore_errors=True)
+    shutil.rmtree(LLVM_BOOTSTRAP_INSTALL_DIR, ignore_errors=True)
+    shutil.rmtree(LLVM_BUILD_DIR, ignore_errors=True)
+
+    build_cmd = [sys.executable, os.path.join(THIS_DIR, 'update.py'),
+                 '--bootstrap', '--force-local-build', '--run-tests']
+    if args.gcc_toolchain is not None:
+      build_cmd.extend(['--gcc-toolchain', args.gcc_toolchain])
+    TeeCmd(build_cmd, log)
+
+  stamp = open(STAMP_FILE).read().rstrip()
+  pdir = 'clang-' + stamp
+  print pdir
+  shutil.rmtree(pdir, ignore_errors=True)
+
+  # Copy a whitelist of files to the directory we're going to tar up.
+  # This supports the same patterns that the fnmatch module understands.
+  exe_ext = '.exe' if sys.platform == 'win32' else ''
+  want = ['bin/llvm-symbolizer' + exe_ext,
+          'lib/clang/*/asan_blacklist.txt',
+          'lib/clang/*/cfi_blacklist.txt',
+          # Copy built-in headers (lib/clang/3.x.y/include).
+          'lib/clang/*/include/*',
+          ]
+  if sys.platform == 'win32':
+    want.append('bin/clang-cl.exe')
+    want.append('bin/lld-link.exe')
+  else:
+    so_ext = 'dylib' if sys.platform == 'darwin' else 'so'
+    want.extend(['bin/clang',
+                 'lib/libFindBadConstructs.' + so_ext,
+                 'lib/libBlinkGCPlugin.' + so_ext,
+                 ])
+  if sys.platform == 'darwin':
+    want.extend(['bin/libc++.1.dylib',
+                 # Copy only the OSX (ASan and profile) and iossim (ASan)
+                 # runtime libraries:
+                 'lib/clang/*/lib/darwin/*asan_osx*',
+                 'lib/clang/*/lib/darwin/*asan_iossim*',
+                 'lib/clang/*/lib/darwin/*profile_osx*',
+                 ])
+  elif sys.platform.startswith('linux'):
+    # Copy only
+    # lib/clang/*/lib/linux/libclang_rt.{[atm]san,san,ubsan,profile}-*.a ,
+    # but not dfsan.
+    want.extend(['lib/clang/*/lib/linux/*[atm]san*',
+                 'lib/clang/*/lib/linux/*ubsan*',
+                 'lib/clang/*/lib/linux/*libclang_rt.san*',
+                 'lib/clang/*/lib/linux/*profile*',
+                 'lib/clang/*/msan_blacklist.txt',
+                 ])
+  elif sys.platform == 'win32':
+    want.extend(['lib/clang/*/lib/windows/clang_rt.asan*.dll',
+                 'lib/clang/*/lib/windows/clang_rt.asan*.lib',
+                 'lib/clang/*/include_sanitizer/*',
+                 ])
+  if args.gcc_toolchain is not None:
+    # Copy the stdlibc++.so.6 we linked Clang against so it can run.
+    want.append('lib/libstdc++.so.6')
+
+  for root, dirs, files in os.walk(LLVM_RELEASE_DIR):
+    # root: third_party/llvm-build/Release+Asserts/lib/..., rel_root: lib/...
+    rel_root = root[len(LLVM_RELEASE_DIR)+1:]
+    rel_files = [os.path.join(rel_root, f) for f in files]
+    wanted_files = list(set(itertools.chain.from_iterable(
+        fnmatch.filter(rel_files, p) for p in want)))
+    if wanted_files:
+      # Guaranteed to not yet exist at this point:
+      os.makedirs(os.path.join(pdir, rel_root))
+    for f in wanted_files:
+      src = os.path.join(LLVM_RELEASE_DIR, f)
+      dest = os.path.join(pdir, f)
+      shutil.copy(src, dest)
+      # Strip libraries.
+      if sys.platform == 'darwin' and f.endswith('.dylib'):
+        # 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.
+        subprocess.call(['install_name_tool', '-id',
+                         '@executable_path/' + os.path.basename(dest), dest])
+        subprocess.call(['strip', '-x', dest])
+      elif (sys.platform.startswith('linux') and
+            os.path.splitext(f)[1] in ['.so', '.a']):
+        subprocess.call(['strip', '-g', dest])
+
+  # Set up symlinks.
+  if sys.platform != 'win32':
+    os.symlink('clang', os.path.join(pdir, 'bin', 'clang++'))
+    os.symlink('clang', os.path.join(pdir, 'bin', 'clang-cl'))
+  if sys.platform == 'darwin':
+    os.symlink('libc++.1.dylib', os.path.join(pdir, 'bin', 'libc++.dylib'))
+    # Also copy libc++ headers.
+    shutil.copytree(os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'include', 'c++'),
+                    os.path.join(pdir, 'include', 'c++'))
+
+  # Copy buildlog over.
+  shutil.copy('buildlog.txt', pdir)
+
+  # Create archive.
+  tar_entries = ['bin', 'lib', 'buildlog.txt']
+  if sys.platform == 'darwin':
+    tar_entries += ['include']
+  with tarfile.open(pdir + '.tgz', 'w:gz') as tar:
+    for entry in tar_entries:
+      tar.add(os.path.join(pdir, entry), arcname=entry, filter=PrintTarProgress)
+
+  if sys.platform == 'darwin':
+    platform = 'Mac'
+  elif sys.platform == 'win32':
+    platform = 'Win'
+  else:
+    platform = 'Linux_x64'
+
+  print 'To upload, run:'
+  print ('gsutil cp -a public-read %s.tgz '
+         'gs://chromium-browser-clang/%s/%s.tgz') % (pdir, platform, pdir)
+
+  # Zip up gold plugin on Linux.
+  if sys.platform.startswith('linux'):
+    golddir = 'llvmgold-' + stamp
+    shutil.rmtree(golddir, ignore_errors=True)
+    os.makedirs(os.path.join(golddir, 'lib'))
+    shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'lib', 'LLVMgold.so'),
+                os.path.join(golddir, 'lib'))
+    with tarfile.open(golddir + '.tgz', 'w:gz') as tar:
+      tar.add(os.path.join(golddir, 'lib'), arcname='lib',
+              filter=PrintTarProgress)
+    print ('gsutil cp -a public-read %s.tgz '
+           'gs://chromium-browser-clang/%s/%s.tgz') % (golddir, platform,
+                                                       golddir)
+
+  # FIXME: Warn if the file already exists on the server.
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/clang/scripts/package.sh b/tools/clang/scripts/package.sh
deleted file mode 100755
index 25cd6f0..0000000
--- a/tools/clang/scripts/package.sh
+++ /dev/null
@@ -1,200 +0,0 @@
-#!/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
index 58a9a86..56cd5d2 100755
--- a/tools/clang/scripts/run_tool.py
+++ b/tools/clang/scripts/run_tool.py
@@ -315,13 +315,14 @@
 
   if len(argv) == 3 and argv[2] == '--all':
     filenames = set(_GetFilesFromCompileDB(argv[1]))
+    source_filenames = filenames
   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)
+    source_filenames = [f for f in filenames
+                        if os.path.splitext(f)[1] in extensions]
+  dispatcher = _CompilerDispatcher(argv[0], argv[1], source_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
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 02488a6..aca7cb9 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -7,77 +7,134 @@
 update.sh. This script should replace update.sh on all platforms eventually."""
 
 import argparse
+import cStringIO
+import distutils.spawn
+import glob
 import os
+import pipes
 import re
 import shutil
 import subprocess
 import stat
 import sys
+import tarfile
+import tempfile
 import time
+import urllib2
+import zipfile
 
 # 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'
+CLANG_REVISION = '254049'
 
-# 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.
-use_head_revision = ('LLVM_FORCE_HEAD_REVISION' in os.environ or
-  not re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')))
+use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ
+if use_head_revision:
+  CLANG_REVISION = 'HEAD'
 
-if not use_head_revision:
-  LLVM_WIN_REVISION = '235968'
+# This is incremented when pushing a new build of Clang at the same revision.
+CLANG_SUB_REVISION=1
+
+PACKAGE_VERSION = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION)
 
 # 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')
+THIRD_PARTY_DIR = os.path.join(CHROMIUM_DIR, 'third_party')
+LLVM_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm')
+LLVM_BOOTSTRAP_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-bootstrap')
+LLVM_BOOTSTRAP_INSTALL_DIR = os.path.join(THIRD_PARTY_DIR,
+                                          'llvm-bootstrap-install')
 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')
+COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, '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'
+# compiler-rt is built as part of the regular LLVM build on Windows to get
+# the 64-bit runtime, and out-of-tree elsewhere.
+# TODO(thakis): Try to unify this.
+if sys.platform == 'win32':
+  COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt')
+else:
+  COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'compiler-rt')
+LIBCXX_DIR = os.path.join(LLVM_DIR, 'projects', 'libcxx')
+LIBCXXABI_DIR = os.path.join(LLVM_DIR, 'projects', 'libcxxabi')
+LLVM_BUILD_TOOLS_DIR = os.path.abspath(
+    os.path.join(LLVM_DIR, '..', 'llvm-build-tools'))
+STAMP_FILE = os.path.join(LLVM_DIR, '..', 'llvm-build', 'cr_build_revision')
+BINUTILS_DIR = os.path.join(THIRD_PARTY_DIR, 'binutils')
+VERSION = '3.8.0'
+ANDROID_NDK_DIR = os.path.join(
+    CHROMIUM_DIR, 'third_party', 'android_tools', 'ndk')
+
+# URL for pre-built binaries.
+CDS_URL = 'https://commondatastorage.googleapis.com/chromium-browser-clang'
 
 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 DownloadUrl(url, output_file):
+  """Download url into output_file."""
+  CHUNK_SIZE = 4096
+  TOTAL_DOTS = 10
+  sys.stdout.write('Downloading %s ' % url)
+  sys.stdout.flush()
+  response = urllib2.urlopen(url)
+  total_size = int(response.info().getheader('Content-Length').strip())
+  bytes_done = 0
+  dots_printed = 0
+  while True:
+    chunk = response.read(CHUNK_SIZE)
+    if not chunk:
+      break
+    output_file.write(chunk)
+    bytes_done += len(chunk)
+    num_dots = TOTAL_DOTS * bytes_done / total_size
+    sys.stdout.write('.' * (num_dots - dots_printed))
+    sys.stdout.flush()
+    dots_printed = num_dots
+  print ' Done.'
+
+
+def DownloadAndUnpack(url, output_dir):
+  with tempfile.TemporaryFile() as f:
+    DownloadUrl(url, f)
+    f.seek(0)
+    if not os.path.exists(output_dir):
+      os.makedirs(output_dir)
+    if url.endswith('.zip'):
+      zipfile.ZipFile(f).extractall(path=output_dir)
+    else:
+      tarfile.open(mode='r:gz', fileobj=f).extractall(path=output_dir)
+
+
 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();
+      return f.read().rstrip()
   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)
+  if not os.path.exists(os.path.dirname(STAMP_FILE)):
+    os.makedirs(os.path.dirname(STAMP_FILE))
   with open(STAMP_FILE, 'w') as f:
     f.write(s)
+    f.write('\n')
 
 
-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)
+def GetSvnRevision(svn_repo):
+  """Returns current revision of the svn repo at svn_repo."""
+  svn_info = subprocess.check_output('svn info ' + svn_repo, shell=True)
   m = re.search(r'Revision: (\d+)', svn_info)
-  assert m
-  print m.group(1)
+  return m.group(1)
 
 
 def RmTree(dir):
@@ -92,12 +149,31 @@
   shutil.rmtree(dir, onerror=ChmodAndRetry)
 
 
-def RunCommand(command, fail_hard=True):
+def RunCommand(command, msvc_arch=None, env=None, fail_hard=True):
   """Run command and return success (True) or failure; or if fail_hard is
-     True, exit on failure."""
+     True, exit on failure.  If msvc_arch is set, runs the command in a
+     shell with the msvc tools for that architecture."""
 
-  print 'Running %s' % (str(command))
-  if subprocess.call(command, shell=True) == 0:
+  if msvc_arch and sys.platform == 'win32':
+    command = GetVSVersion().SetupScript(msvc_arch) + ['&&'] + command
+
+  # https://docs.python.org/2/library/subprocess.html:
+  # "On Unix with shell=True [...] if args is a sequence, the first item
+  # specifies the command string, and any additional items will be treated as
+  # additional arguments to the shell itself.  That is to say, Popen does the
+  # equivalent of:
+  #   Popen(['/bin/sh', '-c', args[0], args[1], ...])"
+  #
+  # We want to pass additional arguments to command[0], not to the shell,
+  # so manually join everything into a single string.
+  # Annoyingly, for "svn co url c:\path", pipes.quote() thinks that it should
+  # quote c:\path but svn can't handle quoted paths on Windows.  Since on
+  # Windows follow-on args are passed to args[0] instead of the shell, don't
+  # do the single-string transformation there.
+  if sys.platform != 'win32':
+    command = ' '.join([pipes.quote(c) for c in command])
+  print 'Running', command
+  if subprocess.call(command, env=env, shell=True) == 0:
     return True
   print 'Failed.'
   if fail_hard:
@@ -114,6 +190,7 @@
 def CopyDirectoryContents(src, dst, filename_filter=None):
   """Copy the files from directory src to dst
   with an optional filename filter."""
+  dst = os.path.realpath(dst)  # realpath() in case dst ends in /..
   if not os.path.exists(dst):
     os.makedirs(dst)
   for root, _, files in os.walk(src):
@@ -125,9 +202,9 @@
 
 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)
+  print "Checking out %s r%s into '%s'" % (name, CLANG_REVISION, dir)
 
-  command = ['svn', 'checkout', '--force', url + '@' + LLVM_WIN_REVISION, dir]
+  command = ['svn', 'checkout', '--force', url + '@' + CLANG_REVISION, dir]
   if RunCommand(command, fail_hard=False):
     return
 
@@ -140,6 +217,8 @@
 
 
 def DeleteChromeToolsShim():
+  OLD_SHIM_DIR = os.path.join(LLVM_DIR, 'tools', 'zzz-chrometools')
+  shutil.rmtree(OLD_SHIM_DIR, ignore_errors=True)
   shutil.rmtree(CHROME_TOOLS_SHIM_DIR, ignore_errors=True)
 
 
@@ -161,27 +240,44 @@
     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')
+    f.write('# dirs, so the build artifacts need to go into a subdirectory.\n')
+    f.write('if (CHROMIUM_TOOLS_SRC)\n')
+    f.write('  add_subdirectory(${CHROMIUM_TOOLS_SRC} ' +
+              '${CMAKE_CURRENT_BINARY_DIR}/a)\n')
+    f.write('endif (CHROMIUM_TOOLS_SRC)\n')
+
+
+def MaybeDownloadHostGcc(args):
+  """Downloads gcc 4.8.2 if needed and makes sure args.gcc_toolchain is set."""
+  if not sys.platform.startswith('linux') or args.gcc_toolchain:
+    return
+
+  if subprocess.check_output(['gcc', '-dumpversion']).rstrip() < '4.7.0':
+    # We need a newer gcc version.
+    gcc_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'gcc482')
+    if not os.path.exists(gcc_dir):
+      print 'Downloading pre-built GCC 4.8.2...'
+      DownloadAndUnpack(CDS_URL + '/tools/gcc482.tgz', LLVM_BUILD_TOOLS_DIR)
+    args.gcc_toolchain = gcc_dir
+  else:
+    # Always set gcc_toolchain; llvm-symbolizer needs the bundled libstdc++.
+    args.gcc_toolchain = \
+        os.path.dirname(os.path.dirname(distutils.spawn.find_executable('gcc')))
 
 
 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)
-
+  """Download CMake and add it to PATH."""
+  if sys.platform == 'win32':
+    zip_name = 'cmake-3.2.2-win32-x86.zip'
+    cmake_dir = os.path.join(LLVM_BUILD_TOOLS_DIR,
+                             'cmake-3.2.2-win32-x86', 'bin')
+  else:
+    suffix = 'Darwin' if sys.platform == 'darwin' else 'Linux'
+    zip_name = 'cmake322_%s.tgz' % suffix
+    cmake_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'cmake322', 'bin')
+  if not os.path.exists(cmake_dir):
+    DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR)
+  os.environ['PATH'] = cmake_dir + os.pathsep + os.environ.get('PATH', '')
 
 vs_version = None
 def GetVSVersion():
@@ -203,152 +299,484 @@
   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 'Updating Clang to %s...' % PACKAGE_VERSION
+  if ReadStampFile() == PACKAGE_VERSION:
     print 'Already up to date.'
     return 0
 
-  AddCMakeToPath()
   # Reset the stamp file in case the build is unsuccessful.
   WriteStampFile('')
 
-  DeleteChromeToolsShim();
+  if not args.force_local_build:
+    cds_file = "clang-%s.tgz" %  PACKAGE_VERSION
+    if sys.platform == 'win32':
+      cds_full_url = CDS_URL + '/Win/' + cds_file
+    elif sys.platform == 'darwin':
+      cds_full_url = CDS_URL + '/Mac/' + cds_file
+    else:
+      assert sys.platform.startswith('linux')
+      cds_full_url = CDS_URL + '/Linux_x64/' + cds_file
+
+    # 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.
+    print 'Trying to download prebuilt clang'
+
+    try:
+      if os.path.exists(LLVM_BUILD_DIR):
+        RmTree(LLVM_BUILD_DIR)
+      DownloadAndUnpack(cds_full_url, LLVM_BUILD_DIR)
+      print 'clang %s unpacked' % PACKAGE_VERSION
+      # Download the gold plugin if requested to by an environment variable.
+      # This is used by the CFI ClusterFuzz bot, and it's required for official
+      # builds on linux.
+      if 'LLVM_DOWNLOAD_GOLD_PLUGIN' in os.environ or (
+          sys.platform.startswith('linux') and
+          'buildtype=Official' in os.environ.get('GYP_DEFINES', '') and
+          'branding=Chrome' in os.environ.get('GYP_DEFINES', '')):
+        RunCommand(['python', CHROMIUM_DIR+'/build/download_gold_plugin.py'])
+      WriteStampFile(PACKAGE_VERSION)
+      return 0
+    except urllib2.HTTPError:
+      print 'Did not find prebuilt clang %s, building locally' % cds_file
+
+  if args.with_android and not os.path.exists(ANDROID_NDK_DIR):
+    print 'Android NDK not found at ' + ANDROID_NDK_DIR
+    print 'The Android NDK is needed to build a Clang whose -fsanitize=address'
+    print 'works on Android. See '
+    print 'http://code.google.com/p/chromium/wiki/AndroidBuildInstructions'
+    print 'for how to install the NDK, or pass --without-android.'
+    return 1
+
+  MaybeDownloadHostGcc(args)
+  AddCMakeToPath()
+
+  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)
+  if sys.platform == 'win32':
+    Checkout('LLD', LLVM_REPO_URL + '/lld/trunk', LLD_DIR)
   Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR)
-  CreateChromeToolsShim();
+  if sys.platform == 'darwin':
+    # clang needs a libc++ checkout, else -stdlib=libc++ won't find includes
+    # (i.e. this is needed for bootstrap builds).
+    Checkout('libcxx', LLVM_REPO_URL + '/libcxx/trunk', LIBCXX_DIR)
+    # 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).
+    Checkout('libcxxabi', LLVM_REPO_URL + '/libcxxabi/trunk', LIBCXXABI_DIR)
+
+  cc, cxx = None, None
+  libstdcpp = None
+  if args.gcc_toolchain:  # This option is only used on Linux.
+    # Use the specified gcc installation for building.
+    cc = os.path.join(args.gcc_toolchain, 'bin', 'gcc')
+    cxx = os.path.join(args.gcc_toolchain, 'bin', 'g++')
+
+    if not os.access(cc, os.X_OK):
+      print 'Invalid --gcc-toolchain: "%s"' % args.gcc_toolchain
+      print '"%s" does not appear to be valid.' % cc
+      return 1
+
+    # Set LD_LIBRARY_PATH to make auxiliary targets (tablegen, bootstrap
+    # compiler, etc.) find the .so.
+    libstdcpp = subprocess.check_output(
+        [cxx, '-print-file-name=libstdc++.so.6']).rstrip()
+    os.environ['LD_LIBRARY_PATH'] = os.path.dirname(libstdcpp)
+
+  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 (nacl...), so for now bundle
+  # libc++.dylib.  Remove this once all bots are on 10.7+, then use
+  # -DLLVM_ENABLE_LIBCXX=ON and change deployment_target to 10.7.
+  deployment_target = ''
+
+  if sys.platform == 'darwin':
+    # 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', subprocess.check_output(
+        ['xcrun', '--show-sdk-path']).rstrip()]
+    cxxflags = ['-stdlib=libc++', '-nostdinc++',
+                '-I' + os.path.join(LIBCXX_DIR, 'include')] + cflags
+    if args.bootstrap:
+      deployment_target = '10.6'
+
+  base_cmake_args = ['-GNinja',
+                     '-DCMAKE_BUILD_TYPE=Release',
+                     '-DLLVM_ENABLE_ASSERTIONS=ON',
+                     '-DLLVM_ENABLE_THREADS=OFF',
+                     ]
+
+  if args.bootstrap:
+    print 'Building bootstrap compiler'
+    if not os.path.exists(LLVM_BOOTSTRAP_DIR):
+      os.makedirs(LLVM_BOOTSTRAP_DIR)
+    os.chdir(LLVM_BOOTSTRAP_DIR)
+    bootstrap_args = base_cmake_args + [
+        '-DLLVM_TARGETS_TO_BUILD=host',
+        '-DCMAKE_INSTALL_PREFIX=' + LLVM_BOOTSTRAP_INSTALL_DIR,
+        '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
+        '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
+        ]
+    if cc is not None:  bootstrap_args.append('-DCMAKE_C_COMPILER=' + cc)
+    if cxx is not None: bootstrap_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
+    RunCommand(['cmake'] + bootstrap_args + [LLVM_DIR], msvc_arch='x64')
+    RunCommand(['ninja'], msvc_arch='x64')
+    if args.run_tests:
+      RunCommand(['ninja', 'check-all'], msvc_arch='x64')
+    RunCommand(['ninja', 'install'], msvc_arch='x64')
+    if args.gcc_toolchain:
+      # Copy that gcc's stdlibc++.so.6 to the build dir, so the bootstrap
+      # compiler can start.
+      CopyFile(libstdcpp, os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'lib'))
+
+    if sys.platform == 'win32':
+      cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe')
+      cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe')
+      # CMake has a hard time with backslashes in compiler paths:
+      # https://stackoverflow.com/questions/13050827
+      cc = cc.replace('\\', '/')
+      cxx = cxx.replace('\\', '/')
+    else:
+      cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang')
+      cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang++')
+
+    if args.gcc_toolchain:
+      # Tell the bootstrap compiler to use a specific gcc prefix to search
+      # for standard library headers and shared object files.
+      cflags = ['--gcc-toolchain=' + args.gcc_toolchain]
+      cxxflags = ['--gcc-toolchain=' + args.gcc_toolchain]
+    print 'Building final compiler'
+
+  if sys.platform == 'darwin':
+    # Build libc++.dylib while some bots are still on OS X 10.6.
+    libcxxbuild = os.path.join(LLVM_BUILD_DIR, 'libcxxbuild')
+    if os.path.isdir(libcxxbuild):
+      RmTree(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.
+    os.makedirs(os.path.join(libcxxbuild, 'libcxx'))
+    os.chdir(os.path.join(libcxxbuild, 'libcxx'))
+    RunCommand(['c++', '-c'] + cxxflags + libcxxflags +
+                glob.glob(os.path.join(LIBCXX_DIR, 'src', '*.cpp')))
+
+    os.makedirs(os.path.join(libcxxbuild, 'libcxxabi'))
+    os.chdir(os.path.join(libcxxbuild, 'libcxxabi'))
+    RunCommand(['c++', '-c'] + cxxflags + libcxxflags +
+               glob.glob(os.path.join(LIBCXXABI_DIR, 'src', '*.cpp')) +
+               ['-I' + os.path.join(LIBCXXABI_DIR, 'include')])
+
+    os.chdir(libcxxbuild)
+    libdir = os.path.join(LIBCXX_DIR, 'lib')
+    RunCommand(['cc'] + glob.glob('libcxx/*.o') + glob.glob('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,' + libdir + '/libc++unexp.exp',
+         '-Wl,-force_symbols_not_weak_list,' + libdir + '/notweak.exp',
+         '-Wl,-force_symbols_weak_list,' + libdir + '/weak.exp'])
+    if os.path.exists('libc++.dylib'):
+      os.remove('libc++.dylib')
+    os.symlink('libc++.1.dylib', 'libc++.dylib')
+    ldflags += ['-stdlib=libc++', '-L' + libcxxbuild]
+
+    if args.bootstrap:
+      # Now that the libc++ headers have been installed and libc++.dylib is
+      # built, delete the libc++ checkout again so that it's not part of the
+      # main build below -- the libc++(abi) tests don't pass on OS X in
+      # bootstrap builds (http://llvm.org/PR24068)
+      RmTree(LIBCXX_DIR)
+      RmTree(LIBCXXABI_DIR)
+      cxxflags = ['-stdlib=libc++', '-nostdinc++',
+                  '-I' + os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR,
+                                      'include/c++/v1')
+                  ] + cflags
+
+  # Build clang.
+  binutils_incdir = ''
+  if sys.platform.startswith('linux'):
+    binutils_incdir = os.path.join(BINUTILS_DIR, 'Linux_x64/Release/include')
+
+  # 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 use_head_revision:
+    cflags += ['-DLLVM_FORCE_HEAD_REVISION']
+    cxxflags += ['-DLLVM_FORCE_HEAD_REVISION']
+
+  # Pin MSan to the old ABI.
+  # TODO(eugenis): Remove when MSan migrates to new ABI (crbug.com/560589).
+  cxxflags += [ '-DMSAN_LINUX_X86_64_OLD_MAPPING' ]
+
+  CreateChromeToolsShim()
+
+  deployment_env = None
+  if deployment_target:
+    deployment_env = os.environ.copy()
+    deployment_env['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
+
+  cmake_args = []
+  # TODO(thakis): Unconditionally append this to base_cmake_args instead once
+  # compiler-rt can build with clang-cl on Windows (http://llvm.org/PR23698)
+  cc_args = base_cmake_args if sys.platform != 'win32' else cmake_args
+  if cc is not None:  cc_args.append('-DCMAKE_C_COMPILER=' + cc)
+  if cxx is not None: cc_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
+  cmake_args += base_cmake_args + [
+      '-DLLVM_BINUTILS_INCDIR=' + binutils_incdir,
+      '-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly',
+      '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
+      '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
+      '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags),
+      '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags),
+      '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags),
+      '-DCMAKE_INSTALL_PREFIX=' + LLVM_BUILD_DIR,
+      '-DCHROMIUM_TOOLS_SRC=%s' % os.path.join(CHROMIUM_DIR, 'tools', 'clang'),
+      '-DCHROMIUM_TOOLS=%s' % ';'.join(args.tools)]
 
   if not os.path.exists(LLVM_BUILD_DIR):
     os.makedirs(LLVM_BUILD_DIR)
   os.chdir(LLVM_BUILD_DIR)
+  RunCommand(['cmake'] + cmake_args + [LLVM_DIR],
+             msvc_arch='x64', env=deployment_env)
 
-  # 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.
-  cflags = cxxflags = ''
+  if args.gcc_toolchain:
+    # Copy in the right stdlibc++.so.6 so clang can start.
+    if not os.path.exists(os.path.join(LLVM_BUILD_DIR, 'lib')):
+      os.mkdir(os.path.join(LLVM_BUILD_DIR, 'lib'))
+    libstdcpp = subprocess.check_output(
+        [cxx] + cxxflags + ['-print-file-name=libstdc++.so.6']).rstrip()
+    CopyFile(libstdcpp, os.path.join(LLVM_BUILD_DIR, 'lib'))
 
-  # TODO(thakis): Set this only conditionally if use_head_revision once posix
-  # and win clang are in sync. At the moment, the plugins only build at clang
-  # head on posix, but they build at both head and the pinned win version :-/
-  cflags += ' -DLLVM_FORCE_HEAD_REVISION'
-  cxxflags += ' -DLLVM_FORCE_HEAD_REVISION'
+  RunCommand(['ninja'], msvc_arch='x64')
 
-  cmake_args = ['-GNinja', '-DCMAKE_BUILD_TYPE=Release',
-                '-DLLVM_ENABLE_ASSERTIONS=ON', SubversionCmakeArg(),
-                '-DCMAKE_C_FLAGS=' + cflags,
-                '-DCMAKE_CXX_FLAGS=' + cxxflags,
-                '-DCHROMIUM_TOOLS_SRC=%s' % os.path.join(
-                    CHROMIUM_DIR, 'tools', 'clang'),
-                '-DCHROMIUM_TOOLS=%s' % ';'.join(args.tools)]
+  if args.tools:
+    # If any Chromium tools were built, install those now.
+    RunCommand(['ninja', 'cr-install'], msvc_arch='x64')
 
-  RunCommand(GetVSVersion().SetupScript('x64') +
-             ['&&', 'cmake'] + cmake_args + [LLVM_DIR])
-  RunCommand(GetVSVersion().SetupScript('x64') + ['&&', 'ninja', 'all'])
+  if sys.platform == 'darwin':
+    CopyFile(os.path.join(libcxxbuild, 'libc++.1.dylib'),
+             os.path.join(LLVM_BUILD_DIR, 'bin'))
+    # See http://crbug.com/256342
+    RunCommand(['strip', '-x', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
+  elif sys.platform.startswith('linux'):
+    RunCommand(['strip', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
 
-  # Do an x86 build of compiler-rt to get the 32-bit ASan run-time.
+  # Do an out-of-tree build of compiler-rt.
+  # On Windows, this is used 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)
+  # On Mac and Linux, this is used to get the regular 64-bit run-time.
+  # Do a clobbered build due to cmake changes.
+  if os.path.isdir(COMPILER_RT_BUILD_DIR):
+    RmTree(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(thakis): Add this once compiler-rt can build with clang-cl (see
+  # above).
+  #if args.bootstrap and sys.platform == 'win32':
+    # The bootstrap compiler produces 64-bit binaries by default.
+    #cflags += ['-m32']
+    #cxxflags += ['-m32']
+  compiler_rt_args = base_cmake_args + [
+      '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
+      '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags)]
+  if sys.platform != 'win32':
+    compiler_rt_args += ['-DLLVM_CONFIG_PATH=' +
+                         os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-config'),
+                        '-DSANITIZER_MIN_OSX_VERSION="10.7"']
+  # compiler-rt is part of the llvm checkout on Windows but a stand-alone
+  # directory elsewhere, see the TODO above COMPILER_RT_DIR.
+  RunCommand(['cmake'] + compiler_rt_args +
+             [LLVM_DIR if sys.platform == 'win32' else COMPILER_RT_DIR],
+             msvc_arch='x86', env=deployment_env)
+  RunCommand(['ninja', 'compiler-rt'], msvc_arch='x86')
 
+  # Copy select output to the main tree.
   # 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')
+  if sys.platform == 'win32':
+    platform = 'windows'
+  elif sys.platform == 'darwin':
+    platform = 'darwin'
+  else:
+    assert sys.platform.startswith('linux')
+    platform = 'linux'
+  asan_rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', platform)
+  if sys.platform == 'win32':
+    # TODO(thakis): This too is due to compiler-rt being part of the checkout
+    # on Windows, see TODO above COMPILER_RT_DIR.
+    asan_rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang',
+                                       VERSION, 'lib', platform)
   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$')
+                                     VERSION, 'lib', platform)
+  # Blacklists:
+  CopyDirectoryContents(os.path.join(asan_rt_lib_src_dir, '..', '..'),
+                        os.path.join(asan_rt_lib_dst_dir, '..', '..'),
+                        r'^.*blacklist\.txt$')
+  # Headers:
+  if sys.platform != 'win32':
+    CopyDirectoryContents(
+        os.path.join(COMPILER_RT_BUILD_DIR, 'include/sanitizer'),
+        os.path.join(LLVM_BUILD_DIR, 'lib/clang', VERSION, 'include/sanitizer'))
+  # Static and dynamic libraries:
+  CopyDirectoryContents(asan_rt_lib_src_dir, asan_rt_lib_dst_dir)
 
-  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)
+  if sys.platform == 'win32':
+    # 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)
 
+  if args.with_android:
+    make_toolchain = os.path.join(
+        ANDROID_NDK_DIR, 'build', 'tools', 'make-standalone-toolchain.sh')
+    for target_arch in ['aarch64', 'arm', 'i686']:
+      # Make standalone Android toolchain for target_arch.
+      toolchain_dir = os.path.join(
+          LLVM_BUILD_DIR, 'android-toolchain-' + target_arch)
+      RunCommand([
+          make_toolchain,
+          '--platform=android-' + ('21' if target_arch == 'aarch64' else '19'),
+          '--install-dir="%s"' % toolchain_dir,
+          '--system=linux-x86_64',
+          '--stl=stlport',
+          '--toolchain=' + {
+              'aarch64': 'aarch64-linux-android-4.9',
+              'arm': 'arm-linux-androideabi-4.9',
+              'i686': 'x86-4.9',
+          }[target_arch]])
+      # Android NDK r9d copies a broken unwind.h into the toolchain, see
+      # http://crbug.com/357890
+      for f in glob.glob(os.path.join(toolchain_dir, 'include/c++/*/unwind.h')):
+        os.remove(f)
+
+      # Build ASan runtime for Android in a separate build tree.
+      build_dir = os.path.join(LLVM_BUILD_DIR, 'android-' + target_arch)
+      if not os.path.exists(build_dir):
+        os.mkdir(os.path.join(build_dir))
+      os.chdir(build_dir)
+      if os.path.exists('CMakeCache.txt'):
+        os.remove('CMakeCache.txt')
+
+      cflags = ['--target=%s-linux-androideabi' % target_arch,
+                '--sysroot=%s/sysroot' % toolchain_dir,
+                '-B%s' % toolchain_dir]
+      android_args = base_cmake_args + [
+        '-DCMAKE_C_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'),
+        '-DCMAKE_CXX_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang++'),
+        '-DLLVM_CONFIG_PATH=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-config'),
+        '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
+        '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags),
+        '-DANDROID=1']
+      RunCommand(['cmake'] + android_args + [COMPILER_RT_DIR])
+      RunCommand(['ninja', 'libclang_rt.asan-%s-android.so' % target_arch])
+
+      # And copy it into the main build tree.
+      runtime = 'libclang_rt.asan-%s-android.so' % target_arch
+      for root, _, files in os.walk(build_dir):
+        if runtime in files:
+          shutil.copy(os.path.join(root, runtime), asan_rt_lib_dst_dir)
+
+  # Run tests.
+  if args.run_tests or use_head_revision:
+    os.chdir(LLVM_BUILD_DIR)
+    RunCommand(['ninja', 'cr-check-all'], msvc_arch='x64')
   if args.run_tests:
     os.chdir(LLVM_BUILD_DIR)
-    RunCommand(GetVSVersion().SetupScript('x64') +
-               ['&&', 'ninja', 'cr-check-all'])
+    RunCommand(['ninja', 'check-all'], msvc_arch='x64')
 
-  WriteStampFile(LLVM_WIN_REVISION)
+  WriteStampFile(PACKAGE_VERSION)
   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('--bootstrap', action='store_true',
+                      help='first build clang with CC, then with itself.')
+  parser.add_argument('--if-needed', action='store_true',
+                      help="run only if the script thinks clang is needed")
+  parser.add_argument('--force-local-build', action='store_true',
+                      help="don't try to download prebuild binaries")
+  parser.add_argument('--gcc-toolchain', help='set the version for which gcc '
+                      'version be used for building; --gcc-toolchain=/opt/foo '
+                      'picks /opt/foo/bin/gcc')
+  parser.add_argument('--print-revision', action='store_true',
+                      help='print current clang revision and exit.')
+  parser.add_argument('--print-clang-version', action='store_true',
+                      help='print current clang version (e.g. x.y.z) and exit.')
+  parser.add_argument('--run-tests', action='store_true',
+                      help='run tests after building; only for local builds')
   parser.add_argument('--tools', nargs='*',
+                      help='select which chrome tools to build',
                       default=['plugins', 'blink_gc_plugin'])
-  # 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')
-  parser.add_argument('--run-tests', action='store_true')
-
+  parser.add_argument('--without-android', action='store_false',
+                      help='don\tt build Android ASan runtime (linux only)',
+                      dest='with_android',
+                      default=sys.platform.startswith('linux'))
   args = parser.parse_args()
 
+  if args.if_needed:
+    is_clang_required = False
+    # clang is always used on Mac and Linux.
+    if sys.platform == 'darwin' or sys.platform.startswith('linux'):
+      is_clang_required = True
+    # clang requested via $GYP_DEFINES.
+    if re.search(r'\b(clang|asan|lsan|msan|tsan)=1',
+                 os.environ.get('GYP_DEFINES', '')):
+      is_clang_required = True
+    # clang previously downloaded, keep it up-to-date.
+    # If you don't want this, delete third_party/llvm-build on your machine.
+    if os.path.isdir(LLVM_BUILD_DIR):
+      is_clang_required = True
+    if not is_clang_required:
+      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
+
+  global CLANG_REVISION, PACKAGE_VERSION
   if args.print_revision:
-    PrintRevision()
+    if use_head_revision:
+      print GetSvnRevision(LLVM_DIR)
+    else:
+      print PACKAGE_VERSION
     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).'
+  if args.print_clang_version:
+    sys.stdout.write(VERSION)
     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
+  # Don't buffer stdout, so that print statements are immediately flushed.
+  # Do this only after --print-revision has been handled, else we'll get
+  # an error message when this script is run from gn for some reason.
+  sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+
+  if use_head_revision:
+    # Use a real revision number rather than HEAD to make sure that the stamp
+    # file logic works.
+    CLANG_REVISION = GetSvnRevision(LLVM_REPO_URL)
+    PACKAGE_VERSION = CLANG_REVISION + '-0'
+
+    args.force_local_build = True
+    if 'OS=android' not in os.environ.get('GYP_DEFINES', ''):
+      # Only build the Android ASan rt on ToT bots when targetting Android.
+      args.with_android = False
 
   return UpdateClang(args)
 
diff --git a/tools/clang/scripts/update.sh b/tools/clang/scripts/update.sh
deleted file mode 100755
index 2e0f0d0..0000000
--- a/tools/clang/scripts/update.sh
+++ /dev/null
@@ -1,709 +0,0 @@
-#!/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}"